CodeGym /בלוג Java /Random-HE /בואו נדבר על מילת מפתח סופית ב-Java
John Squirrels
רָמָה
San Francisco

בואו נדבר על מילת מפתח סופית ב-Java

פורסם בקבוצה
ל-Java יש את מילת המפתח הזו - סופית. ניתן ליישם אותו על מחלקות, שיטות, משתנים (כולל פרמטרים של שיטה). עבור מחלקה, מילת המפתח הסופית פירושה שאין למחלקה תת-מחלקות, כלומר אסורה ירושה... זה שימושי בעת יצירת אובייקטים בלתי ניתנים לשינוי (בלתי ניתנים לשינוי). לדוגמה, המחלקה String מוכרזת כסופית.
public final class String {
}

class SubString extends String { // Compilation error
}
עלי לציין גם שלא ניתן להחיל את השינוי הסופי על מחלקות מופשטות (אלו עם מילת המפתח אבסטרקטית), כי אלו מושגים סותרים זה את זה. עבור שיטה סופית, השינוי אומר שלא ניתן לעקוף את השיטה בתתי מחלקות. זה שימושי כאשר אנו רוצים למנוע את השינוי ביישום המקורי.
public class SuperClass {
    public final void printReport() {
        System.out.println("Report");
    }
}

class SubClass extends SuperClass {
    public void printReport() { //Compilation error
        System.out.println("MyReport");
    }
}
עבור משתנים מסוג פרימיטיבי, מילת המפתח הסופית פירושה שלא ניתן לשנות את הערך לאחר שהוקצה. עבור משתני התייחסות, זה אומר שלאחר הקצאת אובייקט, לא ניתן לשנות את ההפניה לאובייקט זה. זה חשוב! לא ניתן לשנות את ההפניה, אך ניתן לשנות את מצב האובייקט. Java 8 הציגה מושג חדש: סופית למעשה. זה חל רק על משתנים (כולל פרמטרים של שיטה). השורה התחתונה היא שלמרות היעדר ברור של מילת המפתח הסופית, ערך המשתנה אינו משתנה לאחר האתחול. במילים אחרות, ניתן להחיל את מילת המפתח הסופית על משתנה כזה ללא שגיאת קומפילציה. ניתן להשתמש למעשה במשתנים סופיים בתוך מחלקות מקומיות (מחלקות פנימיות מקומיות), מחלקות אנונימיות (מחלקות פנימיות אנונימיות) וזרמים (Stream API).
public void someMethod() {
    // In the example below, both a and b are effectively final, since they are assigned values only once:
    int a = 1;
    int b;
    if (a == 2) b = 3;
    else b = 4;
    // c is NOT effectively final since its value changes
    int c = 10;
    c++;

    Stream.of(1, 2).forEach(s-> System.out.println(s + a)); // OK
    Stream.of(1, 2).forEach(s-> System.out.println(s + c)); // Compilation error
}
עכשיו, בואו נעשה ראיון קטן. אחרי הכל, המטרה של סיום קורס CodeGym היא להפוך למפתח ג'אווה ולמצוא עבודה מעניינת ומשתלמת היטב. אז בואו נתחיל.
  1. מה אנחנו יכולים לומר על מערך שהוכרז כסופי?

  2. אנו יודעים שהמחלקה String אינה ניתנת לשינוי: המחלקה מוכרזת כסופית. ערך מחרוזת מאוחסן במערך char שמסומן במילת המפתח final.

public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence {
    /** The value is used for character storage. */
    private final char value[];
האם נוכל להחליף ערך של אובייקט String (מבלי לשנות את ההתייחסות לאובייקט)? אלו שאלות ראיונות אמיתיות. והתרגול מראה שהרבה מועמדים לא עונים עליהם נכון. חשוב מאוד להבין כיצד משתמשים במילת המפתח הסופית, במיוחד עבור משתני התייחסות. בזמן שאתה חושב על זה, אגיש בקשה קטנה לצוות CodeGym. אנא תן לעורך הטקסט את היכולת להוסיף בלוק שניתן להציג/להסתיר את התוכן שלו כאשר תלחץ עליו. תשובות:
  1. מערך הוא אובייקט, ולכן מילת המפתח הסופית פירושה שברגע שהקצאת הפניה למערך, לא ניתן לשנות את ההפניה. עם זאת, אתה יכול לשנות את מצב האובייקט.

    final int[] array = {1, 2, 3, 4, 5};
    array[0] = 9;	 // OK, because we're changing the contents of the array: {9, 2, 3, 4, 5}
    array = new int[5]; // Compilation error
  2. כן אנחנו יכולים. העיקר להבין מה משמעות מילת המפתח הסופית הקוצנית כאשר משתמשים בה עם אובייקטים. ניתן להשתמש ב-Reflection API כדי להחליף ערכים.

import java.lang.reflect.Field;

class B {
    public static void main(String[] args) throws Exception {
        String value = "Old value";
        System.out.println(value);

        // Get the String class's value field
        Field field = value.getClass().getDeclaredField("value");
        // Make it mutable
        field.setAccessible(true);
        // Set a new value
        field.set(value, "CodeGym".toCharArray());

        System.out.println(value);

        /* Output:
         * Old value
         * CodeGym
         */
    }
}
שימו לב שאם היינו מנסים לשנות את המשתנה הסופי של טיפוס פרימיטיבי בצורה זו, אז שום דבר לא היה קורה. אני מציע שתשכנע את עצמך: צור מחלקת Java, למשל, עם שדה int סופי ונסו לשנות את הערך שלו באמצעות ה-Reflection API. בהצלחה לכולם!
הערות
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION