Słowo kluczowe “final” w Javie

Słowo kluczowe “final” w Javie

Cześć!

     Za nami siedem części wpisów o wątkach. Były to tematy trudne i bardziej zaawansowane. Dzisiaj chciałbym trochę zejść z „wysokiego C” i omówić element jednego z częstych pytań rekrutacyjnych na junior java developera. Pytanie brzmi zazwyczaj: “wymień różnicę między „final”, „finally” oraz finalize wraz z przykładami praktycznymi”. W dzisiejszym wpisie na tapetę weźmy więc słowo kluczowe „final”. No to jedziemy!

Final

     Słowo kluczowe final oznacza, że jeśli zainicjalizujemy coś słowem kluczowym final, to nie możemy modyfikować jej wartości. Słowo kluczowego final możemy użyć w przypadku:  

  • klas
  • metod
  • zmiennych

Klasy finalne

   Klasy oznaczone jako finalne nie mogą być w żaden sposób rozszerzane. Jeśli przeanalizujemy kod bibliotek Javy, możemy tam znaleźć wiele klas finalnych, przykładowo klasa String. Dlaczego? Wyobraźmy sobie sytuacje, w której moglibyśmy rozszerzyć np. wyżej wspomnianą klasę String oraz nadpisać dowolną z jej metod oraz zastąpić wszystkie instancje Stringa instancjami naszej podklasy. W wyniku takiej sytuacji, wszystkie wyniki operacji na obiektach typu String stanie się nieprzewidywalne.

Każda próba dziedziczenia z klasy finalnej spowoduje błąd kompilatora. Rozważmy przykład w praktyce.

Klasy - przykład praktyczny [1]. www.biegajacyprogramista.pl

Spróbujmy teraz tą klasę rozszerzyć:

Klasy - przykład praktyczny [2]. www.biegajacyprogramista.pl

Niestety, kiedy będziemy chcieli skompilować kod, pojawi się błąd:

Klasy - przykład praktyczny [3]. www.biegajacyprogramista.pl

Zwróćmy uwagę na to, że słowo kluczowe final w deklaracji klasy nie oznacza, że obiekty tej klasy są niezmienne. Możemy dowolnie zmieniać pola obiektu:

Klasy - przykład praktyczny [4]. www.biegajacyprogramista.pl

Jeśli przestrzegamy dobrych praktyk programowania oraz projektowania, stworzoną klasę powinniśmy starannie udokumentować lub dla bezpieczeństwa zadeklarować ją jako klasę finalną. Niemniej jednak w praktyce, zwłaszcza kiedy projekt jest w fazach rozwoju uczynienie z góry klasy jako final może być niebezpieczne, ponieważ oznacza to, że żaden programista nie będzie mógł już jej rozszerzać. Wyobraźmy sobie sytuacje, że używamy klasy, nie mając kodu źródłowego i mamy problem z jedną metodą. Jeśli ta klasa jest finalna, nie możemy jej rozszerzyć aby nadpisać metodę i naprawić problem. Innymi słowy: tracimy rozszerzalność, jedną z zalet programowania obiektowego.

Metody finalne

     Metody oznaczone jako finalnie nie mogą być nadpisane. Kiedy projektujemy jakąś klasę i czujemy, że ta metoda nie powinna zostać nigdy nadpisana, możemy uczynić ją finalną. Podobnie jak w przypadku klas, w podstawowych bibliotekach javy możemy znaleźć wiele metod finalnych.

W sytuacji, kiedy nie chcemy całkowicie zabraniać rozszerzania klasy, a jedynie uniemożliwić nadpisywanie niektórych metod, rozwiązanie wydaje się idealne. Dobrym tego przykładem może być klasa Thread. Można ją rozszerzać i w ten sposób stworzyć własną pule wątków, lecz np. jej metoda isAlive() jest finalna i nie możemy jej rozszerzać.

Zobaczmy więc jak to działa w praktyce. Stwórzmy przykładową klasę i zaznaczmy jej jedną z metod jako finalną.

 

Metody - przykład praktyczny [1]. www.biegajacyprogramista.pl

Rozszerzmy teraz klasę Samochod i spróbujmy nadpisać jej metodę kolor():

Metody - przykład praktyczny [2]. www.biegajacyprogramista.pl

Identycznie jak w przypadku klas, ujrzymy wtedy następujący błąd:

Metody - przykład praktyczny [3]. www.biegajacyprogramista.pl

Jeśli niektóre metody naszej klasy są wywoływane przez inne metody, wtedy powinniśmy pomyśleć nad uczynieniem tych metod finalnymi. Jaka jest więc różnica pomiędzy uczynieniem wszystkich metod klasy finalnymi a oznaczaniem samej klasy jako finalnej? W pierwszym przypadku, możemy rozszerzyć klasę i dodać do niej nowe metody. W drugim przypadku nie jest to możliwe.

Zmienne finalne

     Zmienne oznaczone jako finalne nie mogą być ponownie przypisane. Kiedy zmienna finalna zostanie zainicjalizowana, nie może być w żaden sposób zmieniona.

Zmienne prymitywne

     Zadeklarujmy zmienną prymitywną jako zmienną finalną i przypiszmy do niej wartość „10” i spróbujmy później przypisać do niej „20”.

 

Zmienne - przykład praktyczny [1]. www.biegajacyprogramista.pl

Kiedy spróbujemy skompilować projekt, ujrzymy następujący błąd:

Finalne zmienne referencyjne

     Jeśli mamy ostateczną zmienną referencyjną, również nie możemy jej ponownie przypisać. Nie oznacza to jednak, że obiekt do którego się odnosi jest niezmienny. Możemy dowolnie zmieniać właściwości tego obiektu. W praktyce wygląda to tak:

Zmienne - przykład praktyczny [2]. www.biegajacyprogramista.pl

Przy próbie kompilacji ujrzymy następujący błąd:

Zmienne - przykład praktyczny [3]. www.biegajacyprogramista.pl

Nie zmienia to jednak faktu, że wciąż możemy modyfikować obiekty czy pola klasy Samochod.

Finalne pola

     Pola końcowe mogą być zadeklarowane jako stałe lub jako pole typu write-once. Jak je rozróżnić? Powinniśmy zadać sobie następujące pytanie: czy uwzględnilibyśmy to pole, gdybyśmy chcieli serializować obiekt? Jeśli nie, to znaczy, że nie jest to część obiektu, lecz stała.

Zwróćmy uwagę, że zgodnie z konwencją nazewnictwa, stałe klasowe powinny być pisane wielkimi literami, a ich elementy oddzielone znakiem podkreślenia („_”). Przykład:

Zmienne - przykład praktyczny [4]. www.biegajacyprogramista.pl

Warto zwrócić uwagę, że każde pole końcowe musi być zainicjalizowane przed zakończeniem konstruktora.

Dla statycznych pól finalnych oznacza to, że możemy je zainicjalizować w przypadku:

  • deklaracji (jak na powyższym przykładzie)
  • w bloku inicjalizatora statycznego 

Finalne pola oznaczają, że możemy je zainicjalizować w przypadku:

  • deklaracji
  • w bloku inicjalizacji konstruktora
  • w konstruktorze

W przeciwnym razie, kompilacja zakończy się błędem.

Finalne argumenty

     Słowo kluczowe final jest również legalne w przypadku argumentów do metod. Ostateczny argument nie może zostać wtedy zmieniony wewnątrz metody:

Zmienne - przykład praktyczny [5]. www.biegajacyprogramista.pl

Po próbie kompilacji powyższego przykładu, treść błędu będzie następująca:

Zmienne - przykład praktyczny [6. www.biegajacyprogramista.pl

Podsumowanie

     Reasumując, przedstawiłem dzisiaj co oznacza słowo final dla klas, metod oraz zmiennych. Warto co jakiś czas uświadamiać się, że mamy taką możliwość, ponieważ w pędzie dostarczania oprogramowania często można po prostu o tym zapomnieć. W kolejnym poście dotyczącym programowania omówię słowo kluczowe „finally”.

Pozdrawiam serdecznie,
biegajacyprogramista.pl

Dodaj komentarz

13 + 4 =

Close Menu