W Javie jest słowo kluczowe -
final
. Można go zastosować do klas, metod, zmiennych (w tym argumentów metod). W 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 String
zadeklarowanej 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
), final
ponieważ są to pojęcia wzajemnie się wykluczające. Metoda bowiem final
oznacza, ż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 final
wartość zmiennej po inicjalizacji nie ulega zmianie. Innymi słowy, możesz zastąpić słowo taką zmienną final
bez błędu kompilacji. effectively final
Zmiennych 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.
-
Co można powiedzieć o tablicy, gdy jest ona zadeklarowana
final
? -
Wiadomo, że klasa
String
jestimmutable
, klasa jest zadeklarowanafinal
, wartość ciągu jest przechowywana w tablicychar
, która jest oznaczona słowem kluczowymfinal
.
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:
-
Ponieważ tablica jest obiektem, co
final
oznacza, ż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
-
Tak, możesz. Kluczem jest zrozumienie użycia słowa kolczastego
final
w 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 int
polem i spróbuj zmienić jej wartość poprzez API Reflection. Powodzenia wszystkim!
GO TO FULL VERSION