JavaRush /בלוג Java /Random-HE /אז סופי...
Алексей
רָמָה

אז סופי...

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

class SubString extends String{ //Compilation error
}
כמו כן, יש לציין שלא ניתן להחיל את השינוי על מחלקות מופשטות (עם מילת המפתח abstract), finalכי אלו מושגים סותרים זה את זה. עבור שיטה finalפירושו שלא ניתן לעקוף אותה בתתי מחלקות. זה שימושי כאשר אנו רוצים שהיישום המקורי לא יעקוף.
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 הופיע המושג - effectively final. זה חל רק על משתנים (כולל ארגומנטים של שיטה). הנקודה היא שלמרות ההיעדר הברור של מילת המפתח final, הערך של המשתנה לא משתנה לאחר האתחול. במילים אחרות, אתה יכול להחליף מילה במשתנה כזה finalללא שגיאת קומפילציה. effectively finalניתן להשתמש במשתנים בתוך מחלקות מקומיות ( Local Inner Classes), מחלקות אנונימיות ( Anonymous Inner Classes), זרמים (Stream API).
public void someMethod(){
    // In the example below, both a and b are effectively final, since the values ​​are set once:
    int a = 1;
    int b;
    if (a == 2) b = 3;
    else b = 4;
    // c is NOT effectively final because value changes
    int c = 10;
    c++;

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

  2. ידוע שהמחלקה Stringהיא immutable, המחלקה מוצהרת final, הערך של המחרוזת מאוחסן במערך 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(מבלי לשנות את ההתייחסות לאובייקט)? אלו שאלות ראיונות אמיתיות. וכפי שמראה בפועל, רבים עונים עליהם בצורה שגויה. הבנת השימוש במילת המפתח final, במיוחד עבור משתני התייחסות, חשובה מאוד. בזמן שאתה חושב, סטייה מהירה לצוות JavaRush. אנא הוסף בלוק בעורך הטקסט שלך המאפשר לך להסתיר את התוכן, וכשתלחץ עליו, הצג את התוכן הזה. תשובות:
  1. כי מערך הוא אובייקט, מה finalשאומר שאחרי הקצאת הפניה לאובייקט, לא ניתן עוד לשנות אותו, אך ניתן לשנות את מצב האובייקט.

    final int[] array = {1,2,3,4,5};
    array[0] = 9;	//ok, because change the contents of the array - {9,2,3,4,5}
    array = new int[5]; //compile error
  2. כן אתה יכול. המפתח הוא להבין את השימוש במילה הדוקרנית finalעם חפצים. משתמש ב-ReflectionAPI כדי להחליף את הערך.

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 value field in the String class
        Field field = value.getClass().getDeclaredField("value");
        //Let's change it
        field.setAccessible(true);
        //Set new value
        field.set(value, "JavaRush".toCharArray());

        System.out.println(value);

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