JavaRush /Blog Java /Random-PL /Tak ostateczna...
Алексей
Poziom 32

Tak ostateczna...

Opublikowano w grupie Random-PL
W Javie jest słowo kluczowe - final. Można go zastosować do klas, metod, zmiennych (w tym argumentów metod). Tak ostatecznie... - 1W przypadku klasy oznacza to, że klasa nie może mieć podklas, tj. Dziedziczenie jest zabronione. Jest to przydatne podczas tworzenia immutable(niezmiennych) obiektów, na przykład klasy Stringzadeklarowanej jako final.
public final class String{
}

class SubString extends String{ //Błąd kompilacji
}
Należy również zauważyć, że modyfikatora nie można zastosować do klas abstrakcyjnych (ze słowem kluczowym abstract), finalponieważ są to pojęcia wzajemnie się wykluczające. Metoda bowiem finaloznacza, że ​​nie można jej zastąpić w podklasach. Jest to przydatne, gdy chcemy, aby oryginalna implementacja nie została zastąpiona.
public class SuperClass{
    public final void printReport(){
        System.out.println("Report");
    }
}

class SubClass extends SuperClass{
    public void printReport(){  //Błąd kompilacji
        System.out.println("MyReport");
    }
}
W przypadku zmiennych typu pierwotnego oznacza to, że raz przypisanej wartości nie można zmienić. W przypadku zmiennych referencyjnych oznacza to, że po przypisaniu obiektu nie można zmienić odniesienia do tego obiektu. To jest ważne! Nie można zmienić łącza, ale można zmienić stan obiektu. W Javie 8 pojawiła się koncepcja - effectively final. Dotyczy tylko zmiennych (w tym argumentów metod). Chodzi o to, że pomimo oczywistego braku słowa kluczowego finalwartość zmiennej po inicjalizacji nie ulega zmianie. Innymi słowy, możesz zastąpić słowo taką zmienną finalbez błędu kompilacji. effectively finalZmiennych można używać wewnątrz klas lokalnych ( Local Inner Classes), klas anonimowych ( Anonymous Inner Classes), strumieni (Stream API).
public void someMethod(){
    // W poniższym przykładzie zarówno a, jak i b są faktycznie ostateczne, ponieważ wartości są ustawiane raz:
    int a = 1;
    int b;
    if (a == 2) b = 3;
    else b = 4;
    // c NIE jest faktycznie ostateczne, ponieważ zmiany wartości
    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)); //Błąd kompilacji
}
Teraz przeprowadzimy mały wywiad. W końcu celem kursu JavaRush jest zostanie programistą Java i zdobycie ciekawej i dobrze płatnej pracy. Zacznijmy więc.
  1. Co można powiedzieć o tablicy, gdy jest ona zadeklarowana final?

  2. Wiadomo, że klasa Stringjest immutable, klasa jest zadeklarowana final, wartość ciągu jest przechowywana w tablicy char, która jest oznaczona słowem kluczowym final.

public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence {
    /** The value is used for character storage. */
    private final char value[];
Czy można zastąpić wartość obiektu String(bez zmiany odniesienia do obiektu)? To są prawdziwe pytania na rozmowie kwalifikacyjnej. I jak pokazuje praktyka, wielu odpowiada na nie niepoprawnie. Zrozumienie użycia słowa kluczowego final, szczególnie w przypadku zmiennych referencyjnych, jest bardzo ważne. Podczas gdy się zastanawiasz, krótka dygresja do zespołu JavaRush. Proszę dodać blok w swoim edytorze tekstu, który pozwoli Ci ukryć treść, a po kliknięciu wyświetli tę treść. Odpowiedzi:
  1. Ponieważ tablica jest obiektem, co finaloznacza, że ​​po przypisaniu referencji do obiektu nie można już jej zmienić, ale można zmienić stan obiektu.

    final int[] array = {1,2,3,4,5};
    array[0] = 9;	//ok, ponieważ zmień zawartość tablicy - {9,2,3,4,5}
    array = new int[5]; //błąd kompilacji
  2. Tak, możesz. Kluczem jest zrozumienie użycia słowa kolczastego finalw odniesieniu do przedmiotów. Używa ReflectionAPI do zastąpienia wartości.

import java.lang.reflect.Field;

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

        //Pobierz pole wartości w klasie String
        Field field = value.getClass().getDeclaredField("value");
        //Zmieńmy to
        field.setAccessible(true);
        //Ustaw nową wartość
        field.set(value, "JavaRush".toCharArray());

        System.out.println(value);

        /* Вывод:
         * Old value
         * JavaRush
         */
    }
}
Pamiętaj, że gdybyśmy próbowali w ten sposób zmienić zmienną końcową typu pierwotnego, nic by nie zadziałało. Proponuję się o tym przekonać: utwórz na przykład klasę Java z final intpolem i spróbuj zmienić jej wartość poprzez API Reflection. Powodzenia wszystkim!
Komentarze
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION