W Javie używamy final
słowa kluczowego ze zmiennymi, aby określić, że jego wartości nie będą zmieniane. Ale widzę, że możesz zmienić wartość w konstruktorze / metodach klasy. Ponownie, jeśli zmienna jest, static
to jest to błąd kompilacji.
Oto kod:
import java.util.ArrayList;
import java.util.List;
class Test {
private final List foo;
public Test()
{
foo = new ArrayList();
foo.add("foo"); // Modification-1
}
public static void main(String[] args)
{
Test t = new Test();
t.foo.add("bar"); // Modification-2
System.out.println("print - " + t.foo);
}
}
Powyższy kod działa poprawnie i nie zawiera błędów.
Teraz zmień zmienną jako static
:
private static final List foo;
Teraz jest to błąd kompilacji. Jak to final
naprawdę działa?
Odpowiedzi:
Jesteś zawsze mogą zainicjować jest
final
zmienną. Kompilator zapewnia, że możesz to zrobić tylko raz.Zauważ, że wywoływanie metod na obiekcie przechowywanym w
final
zmiennej nie ma nic wspólnego z semantykąfinal
. Innymi słowy:final
dotyczy tylko samego odwołania, a nie zawartości odnośnego obiektu.Java nie ma pojęcia niezmienności obiektu; osiąga się to poprzez staranne zaprojektowanie obiektu i jest to przedsięwzięcie dalekie od trywialności.
źródło
final
. Zmienne obiekty można również przypisywać do stosu.final
pola mogą jednak pomóc w analizie ucieczki, ale jest to dość pośrednia droga. Zauważ również, że efektywnie zmienne końcowe mają identyczne traktowanie jak zmienne zaznaczonefinal
w kodzie źródłowym.final
jest obecny w pliku klasy i ma znaczące konsekwencje semantyczne dla optymalizującego środowiska wykonawczego. Może to również powodować koszty, ponieważ JLS ma silną gwarancję spójnościfinal
pól obiektu. Na przykład procesor ARM musi użyć wyraźnej instrukcji bariery pamięci na końcu każdego konstruktora klasy, która mafinal
pola. W przypadku innych procesorów nie jest to jednak konieczne.To jest ulubione pytanie do wywiadu . Na podstawie tych pytań ankieter próbuje dowiedzieć się, jak dobrze rozumiesz zachowanie obiektów w odniesieniu do konstruktorów, metod, zmiennych klas (zmiennych statycznych) i zmiennych instancji.
W powyższym przypadku zdefiniowaliśmy konstruktor dla „Testu” i nadaliśmy mu metodę „setFoo”.
O konstruktora: Konstruktor może być wywołany tylko jeden raz na tworzenie obiektów za pomocą
new
słowa kluczowego. Nie można wywoływać konstruktora wiele razy, ponieważ konstruktor nie jest do tego przeznaczony.Informacje o metodzie: Metodę można wywołać dowolną liczbę razy (nawet nigdy), a kompilator o tym wie.
Scenariusz 1
foo
jest zmienną instancji . Kiedy tworzymyTest
obiekt klasy, wówczas zmienna instancjifoo
zostanie skopiowana do obiektuTest
klasy. Jeśli przypiszemyfoo
do konstruktora, to kompilator wie, że konstruktor zostanie wywołany tylko raz, więc nie ma problemu z przypisaniem go do konstruktora.Jeśli przypiszemy
foo
wewnątrz metody, kompilator wie, że metodę można wywołać wiele razy, co oznacza, że wartość będzie musiała zostać zmieniona wiele razy, co nie jest dozwolone dlafinal
zmiennej. Kompilator decyduje więc, że konstruktor jest dobrym wyborem! Możesz przypisać wartość do zmiennej końcowej tylko raz.Scenariusz 2
foo
jest teraz zmienną statyczną . Kiedy tworzymy instancjęTest
klasy,foo
nie zostanie ona skopiowana do obiektu, ponieważfoo
jest statyczna. Terazfoo
nie jest niezależną własnością każdego obiektu. Jest to właściwośćTest
klasy. Alefoo
może być widoczny dla wielu obiektów i jeśli każdy obiekt utworzony przy użyciunew
słowa kluczowego, które ostatecznie wywołaTest
konstruktor, który zmienia wartość w momencie tworzenia wielu obiektów (Pamiętaj, żestatic foo
nie jest kopiowany w każdym obiekcie, ale jest dzielony między wieloma obiektami .)Scenariusz 3
Powyżej
Modification-2
jest z twojego pytania. W powyższym przypadku nie zmieniasz pierwszego obiektu, do którego istnieje odwołanie, ale dodajesz zawartość,foo
która jest dozwolona. Kompilator narzeka jeśli spróbujesz przypisaćnew ArrayList()
dofoo
zmiennej referencyjnej.Reguła Jeśli zainicjowałeś
final
zmienną, nie możesz jej zmienić tak, aby odwoływała się do innego obiektu. (W tym przypadkuArrayList
)klas końcowych nie można podklasować. Metody
końcowe nie mogą zostać zastąpione. (Ta metoda jest w nadklasie) metody
końcowe mogą zostać zastąpione. (Przeczytaj to gramatycznie. Ta metoda należy do podklasy)
źródło
foo
byłby ustawiany wiele razy pomimo ostatecznego oznaczenia, gdybyfoo
ustawiono go w klasie Test i utworzono wiele instancji Testu?foo
może być ... wiele obiektów.) Czy to znaczy, że jeśli tworzę wiele obiektów jednocześnie, to który obiekt inicjuje zmienną końcową zależy od wykonania?final
do adresu pamięci, dofoo
którego odwołuje się ArrayList. Nie przypisujeszfinal
adresu pamięci, do którego odwołuje się pierwszy elementfoo
(lub dowolny element w tym zakresie). Dlatego nie możesz się zmienić,foo
ale możesz się zmienićfoo[0]
.foo = new ArrayList();
-foo
odnosi się do zmiennej statycznej, ponieważ jesteśmy w tej samej klasie.final
zmienną jako taką samą jakconst
słowo kluczowe w C ++?Ostateczne słowo kluczowe ma wiele sposobów użycia:
Inne zastosowanie:
Zmienna klasy statycznej będzie istnieć od początku JVM i powinna zostać zainicjowana w klasie. Komunikat o błędzie nie pojawi się, jeśli to zrobisz.
źródło
static
pola (o ile nie sąfinal
) tyle razy, ile chcesz. Zobacz tę wiki, aby zobaczyć różnicę między przypisaniem a inicjalizacją .The
final
kluczowe można interpretować na dwa różne sposoby, w zależności od tego, na czym jest używane:Typy wartości: dla
int
s,double
s itp. Zapewni, że wartość nie może się zmienić,Typy referencji: W przypadku referencji do obiektów
final
zapewnia, że referencja nigdy się nie zmieni, co oznacza, że zawsze będzie odnosić się do tego samego obiektu. Nie daje żadnej gwarancji, że wartości wewnątrz obiektu będą takie same.Jako taki
final List<Whatever> foo;
zapewnia, żefoo
zawsze odnosi się do tej samej listy, ale zawartość tej listy może się zmieniać z czasem.źródło
Jeśli zrobisz
foo
statyczny, musisz zainicjować go w konstruktorze klas (lub wstawić tam, gdzie go zdefiniujesz), tak jak w poniższych przykładach.Konstruktor klas (nie instancja):
Inline:
Problemem nie jest tutaj działanie
final
modyfikatora, ale raczej działaniestatic
modyfikatora.final
Modyfikator wymusza inicjalizacja odniesienia do czasu połączenie do dopełnia konstruktorów (czyli trzeba go zainicjować w konstruktorze).Po zainicjowaniu atrybutu in-line zostaje on zainicjowany przed uruchomieniem kodu zdefiniowanego dla konstruktora, dzięki czemu uzyskuje się następujące wyniki:
foo
jeststatic
,foo = new ArrayList()
zostanie wykonane przed wykonaniemstatic{}
konstruktora zdefiniowanego dla twojej klasyfoo
niestatic
,foo = new ArrayList()
zostanie wykonany przed uruchomieniem konstruktoraJeśli nie zainicjujesz atrybutu w linii,
final
modyfikator wymusza jego inicjalizację i musisz to zrobić w konstruktorze. Jeśli masz równieżstatic
modyfikator, konstruktorem, w którym będziesz musiał zainicjować atrybut, jest blok inicjalizacji klasy:static{}
.Błąd, który
static{}
pojawia się w kodzie, wynika z faktu, że jest uruchamiany podczas ładowania klasy, przed momentem utworzenia obiektu tej klasy. Dlatego nie zainicjujesz sięfoo
podczas tworzenia klasy.Pomyśl o
static{}
bloku jako konstruktorze obiektu typuClass
. W tym miejscu musisz wykonać inicjalizacjęstatic final
atrybutów klasy (jeśli nie jest to wykonywane bezpośrednio).Dygresja:
W
final
modyfikator zapewnieniu jak const-ności tylko dla typów pierwotnych i referencje.Kiedy deklarujesz
final
obiekt, otrzymujeszfinal
odniesienie do tego obiektu, ale sam obiekt nie jest stały.Deklarując
final
atrybut, naprawdę osiągasz to, że po zadeklarowaniu obiektu do określonego celu (takiego jak tenfinal List
, który zadeklarowałeś), tylko ten obiekt zostanie wykorzystany do tego celu: nie będziesz mógł zmienićList foo
na innyList
, ale nadal możesz zmienić swojeList
, dodając / usuwając elementy (List
używasz będzie taki sam, tylko ze zmienioną zawartością).źródło
To bardzo dobre pytanie podczas rozmowy kwalifikacyjnej. Czasami mogą nawet zapytać, jaka jest różnica między ostatecznym obiektem a niezmiennym przedmiotem.
1) Gdy ktoś wspomina o obiekcie końcowym, oznacza to, że odwołania nie można zmienić, ale jego stan (zmienne instancji) można zmienić.
2) Niezmienny obiekt to taki, którego stanu nie można zmienić, ale można zmienić jego odniesienie. Dawny:
zmienną ref x można zmienić, aby wskazywała inny ciąg, ale nie można zmienić wartości „abc”.
3) Zmienne instancji (pola niestatyczne) są inicjowane, gdy wywoływany jest konstruktor. Możesz więc inicjalizować wartości dla zmiennych wewnątrz konstruktora.
4) „Ale widzę, że możesz zmienić wartość w konstruktorze / metodach klasy”. - Nie możesz tego zmienić wewnątrz metody.
5) Zmienna statyczna jest inicjowana podczas ładowania klasy. Więc nie możesz zainicjować wewnątrz konstruktora, musisz to zrobić jeszcze przed nim. Musisz więc przypisać wartości do zmiennej statycznej podczas samej deklaracji.
źródło
Słowo
final
kluczowe w java służy do ograniczenia użytkownika. Słowofinal
kluczowe java może być używane w wielu kontekstach. Finał może być:Słowo
final
kluczowe może być stosowane ze zmiennymi,final
zmienna, która nie ma wartości, nazywa sięfinal
zmienną pustą lubfinal
zmienną niezainicjowaną . Można go zainicjować tylko w konstruktorze.final
Zmienna pusta może byćstatic
również inicjowana tylko wstatic
bloku.Ostateczna zmienna Java:
Jeśli się dowolną zmienną jak
final
, to nie można zmienić wartości wfinal
zmiennej (To będzie stała).Przykład
final
zmiennejIstnieje końcowa zmienna speedlimit, zmienimy wartość tej zmiennej, ale nie można jej zmienić, ponieważ zmiennej końcowej po przypisaniu wartości nigdy nie można zmienić.
Ostatnia klasa Java:
Jeśli utworzysz dowolną klasę jako
final
, nie możesz jej rozszerzyć .Przykład końcowej klasy
Ostateczna metoda Java:
Jeśli dowolna metoda zostanie uznana za ostateczną, nie można jej zastąpić .
Przykład
final
metody (run () w Hondzie nie może zastąpić run () w Bike)udostępnione z: http://www.javatpoint.com/final-keyword
źródło
Warto wspomnieć o kilku prostych definicjach:
Klasy / metody
Zmienne
final
w zasadzie unikaj nadpisywania / nadpisywania przez cokolwiek (podklasy, zmienna „zmiana przypisania”), w zależności od przypadku.źródło
final
jest zastrzeżonym słowem kluczowym w Javie w celu ograniczenia użytkownika i może być stosowane do zmiennych składowych, metod, klas i zmiennych lokalnych. Ostateczne zmienne są często deklarowane za pomocąstatic
słowa kluczowego w Javie i są traktowane jako stałe. Na przykład:Kiedy używamy
final
słowa kluczowego z deklaracją zmiennej, wartości przechowywanej w tej zmiennej nie można później zmienić.Na przykład:
Uwaga : Klasa zadeklarowana jako końcowa nie może być rozszerzana ani dziedziczona (tzn. Nie może istnieć podklasa superklasy). Warto również zauważyć, że metody zadeklarowane jako końcowe nie mogą zostać zastąpione przez podklasy.
Korzyści ze stosowania końcowego słowa kluczowego są omówione w tym wątku .
źródło
the value stored inside that variable cannot be changed latter
jest częściowo prawdziwe. Dotyczy to tylko pierwotnych typów danych. W przypadku dowolnego obiektu utworzonegofinal
, podobnie jak arraylist, jego wartość może ulec zmianie, ale nie odwołanie. Dziękuję Ci!Załóżmy, że masz dwie skarbonki, czerwoną i białą. Skarbonki przypisujesz tylko dwóm dzieciom i nie wolno im zamieniać swoich pudełek. Masz więc czerwone lub białe skarbonki (końcowe), więc nie możesz modyfikować pudełka, ale możesz włożyć pieniądze na swoje pudełko.
źródło
Przeczytaj wszystkie odpowiedzi.
Istnieje inny przypadek użytkownika, w którym
final
można użyć słowa kluczowego, tj. W argumencie metody:Może być użyty do zmiennej, której nie należy zmieniać.
źródło
Po ustawieniu go na statyczny jako ostateczny, należy go zainicjalizować w bloku inicjalizacji statycznej
źródło
Słowo
final
kluczowe wskazuje, że zmienną można zainicjować tylko raz. W kodzie wykonujesz tylko jedną inicjalizację finału, więc warunki są spełnione. Ta instrukcja wykonuje samotną inicjalizacjęfoo
. Zauważ, żefinal
! = Niezmienny, oznacza to tylko, że odwołanie nie może się zmienić.Kiedy deklarujesz
foo
jakostatic final
zmienna musi być inicjowane, gdy klasa jest załadowany i nie można polegać na konkretyzacji (aka zadzwonić do konstruktora), aby zainicjowaćfoo
od pola statyczne muszą być dostępne bez instancji klasy. Nie ma gwarancji, że konstruktor zostanie wywołany przed użyciem pola statycznego.Gdy wykonasz metodę w tym
static final
scenariuszu,Test
klasa jest ładowana przed utworzeniem instancjit
w tym momencie, nie ma instancji,foo
co oznacza, że nie została zainicjowana, więcfoo
jest ustawiona na wartość domyślną dla wszystkich obiektów, które sąnull
. W tym momencie zakładam, że Twój kod rzuca,NullPointerException
gdy próbujesz dodać element do listy.źródło
Po pierwsze, miejsce w twoim kodzie, w którym inicjujesz (tj. Przypisujesz po raz pierwszy) foo jest tutaj:
foo jest obiektem (z typem List), więc jest typem referencyjnym , a nie typem wartości (jak int). Jako taki zawiera odniesienie do lokalizacji w pamięci (np. 0xA7D2A834), w której przechowywane są elementy listy. Takie linie
nie zmieniaj wartości foo (która znowu jest tylko odniesieniem do lokalizacji w pamięci). Zamiast tego po prostu dodają elementy do wskazanej lokalizacji pamięci. Aby naruszyć końcowe słowo kluczowe, musisz spróbować ponownie przypisać foo w następujący sposób:
Że byłoby dać błąd kompilacji.
Teraz, mając to na uwadze, zastanów się, co się stanie, gdy dodasz słowo kluczowe static .
Jeśli NIE masz statycznego słowa kluczowego, każdy obiekt, który tworzy instancję klasy, ma własną kopię foo. Dlatego konstruktor przypisuje wartość do pustej, świeżej kopii zmiennej foo, co jest całkowicie w porządku.
Jednakże, gdy masz słowo kluczowe static, w pamięci istnieje tylko jedna foo powiązana z klasą. Jeśli chcesz utworzyć dwa lub więcej obiektów, konstruktor będzie próbował za każdym razem ponownie przypisać ten jeden foo, naruszając ostateczne słowo kluczowe.
źródło
final
po prostu wiąże odniesienie do określonego obiektu. Możesz zmienić „stan” tego obiektu, ale nie sam obiekt.źródło
Poniżej przedstawiono różne konteksty, w których używany jest finał.
Zmienne końcowe Ostatnią zmienną można przypisać tylko raz. Jeśli zmienna jest odwołaniem, oznacza to, że zmiennej nie można ponownie powiązać z odniesieniem do innego obiektu.
zmiennej końcowej można przypisać wartość później (nieobowiązkowo przypisać wartość, gdy zostanie zadeklarowana), ale tylko raz.
Klasy końcowe Klasy końcowej nie można przedłużać (dziedziczone)
Ostateczne metody Ostatecznej metody nie można zastąpić podklasami.
źródło
Myślałem o napisaniu tutaj zaktualizowanej i dogłębnej odpowiedzi.
final
słowa kluczowego można użyć w kilku miejscach.A
final class
oznacza, że żaden inny klasa może przedłużyć ten ostateczny klasie. Gdy Java Run Time ( JRE ) wie, że odwołanie do obiektu jest w rodzaju klasy końcowej (powiedzmy F), wie, że wartość tego odwołania może być tylko typu F.Dawny:
Kiedy więc wykonuje jakąkolwiek metodę tego obiektu, tej metody nie trzeba rozwiązywać w czasie wykonywania przy użyciu wirtualnej tabeli . tzn. nie można zastosować polimorfizmu w czasie wykonywania. Czas wykonywania nie zawraca sobie tym głowy. Co oznacza, że oszczędza czas przetwarzania, co poprawi wydajność.
A
final method
dowolnej klasy oznacza, że żadna klasa potomna rozszerzająca tę klasę nie może przesłonić ostatecznych metod. Zatem zachowanie w czasie wykonywania w tym scenariuszu jest również takie samo, jak poprzednie zachowanie, o którym wspominałem dla klas.Jeśli określono jakikolwiek z powyższych elementów jako
final
, oznacza to, że wartość jest już sfinalizowana, więc wartości nie można zmienić .Dawny:
W przypadku pól parametry lokalne
Dla parametrów metody
Oznacza to po prostu, że wartości wartości
final
odniesienia nie można zmienić. tzn. dozwolona jest tylko jedna inicjalizacja. W tym scenariuszu w czasie wykonywania, ponieważ środowisko JRE wie, że wartości nie można zmienić, ładuje wszystkie te ostateczne wartości (ostatecznych odniesień) do pamięci podręcznej L1 . Ponieważ nie trzeba go ponownie ładować z pamięci głównej . W przeciwnym razie ładuje się do pamięci podręcznej L2 i od czasu do czasu ładuje się z pamięci głównej. Jest to więc także poprawa wydajności.Tak więc we wszystkich powyższych 3 scenariuszach, gdy nie określiliśmy
final
słowa kluczowego w miejscach, których możemy użyć, nie musimy się martwić, optymalizacje kompilatora zrobią to za nas. Istnieje również wiele innych rzeczy, które optymalizacje kompilatora robią dla nas. :)źródło
Przede wszystkim są poprawne. Ponadto, jeśli nie chcesz, aby inni tworzyli podklasy z twojej klasy, zadeklaruj swoją klasę jako ostateczną. Następnie poziom liścia w hierarchii drzewa klasowego staje się tym, że nikt nie może go dalej rozszerzać. Dobrą praktyką jest unikanie ogromnej hierarchii klas.
źródło