Sobes.tech
Junior

W jakich przypadkach można zastosować modyfikator final w Java?

sobes.tech AI

Odpowiedź od AI

Modyfikator final w Javie można stosować do:

  1. Zmiennych:

    • Zmienne lokalne: Ich wartość jest przypisywana raz i nie może być zmieniona po inicjalizacji.
    • Pola klasy: Wartość pola jest przypisywana podczas deklaracji lub w konstruktorze i potem nie może być zmieniona.
    • Parametry metody: Parametr wewnątrz metody staje się stałą; nie można go przepisać w ciele metody.

    Zastosowanie final do zmiennych zapewnia:

    • Niezmienność: Gwarancja, że wartość się nie zmieni.
    • Bezpieczeństwo wątków: Pola final klasy są widoczne dla wszystkich wątków po zakończeniu konstruktora bez dodatkowej synchronizacji.
    • Optymalizacje kompilatora: Kompilator może wykonywać pewne optymalizacje, wiedząc, że wartość się nie zmieni.
  2. Metod:

    • Metoda zadeklarowana jako final nie może być nadpisana w podklasach.
    • Jest to przydatne do:
      • Zapobiegania niepożądanym zmianom zachowania: Gwarantuje, że logika metody pozostanie niezmieniona.
      • Wspierania kompozycji: Zachęca do używania kompozycji zamiast dziedziczenia.
      • Możliwe optymalizacje kompilatora: Kompilator może wykonywać inlining wywołań final metod.
  3. Klasy:

    • Klasa zadeklarowana jako final nie może mieć podklas.
    • Zastosowanie final do klasy służy do:
      • Tworzenia niezmiennych (immutable) klas: Na przykład klas opakowujących typy prymitywne (Integer, String).
      • Ochrony projektu: Zapobiega rozszerzaniu, które mogłoby naruszyć invariants klasy.
      • Zwiększenia bezpieczeństwa: Gwarantuje, że zachowanie klasy nie może być zmienione przez tworzenie podklas.
Zastosowanie Opis Zalety
final pole Wartość jest przypisywana raz (przy deklaracji lub w konstruktorze). Niezmienność, bezpieczeństwo wątków, optymalizacje.
final parametr Wartość nie może być zmieniona wewnątrz metody. Jasna sygnatura, gwarancja niezmienności wartości parametru.
final metoda Nie może być nadpisana w podklasach. Zapobieganie zmianom zachowania, wspieranie kompozycji, optymalizacje.
final klasa Nie może mieć podklas (niemożliwe dziedziczenie). Niezmienna klasa, ochrona projektu, zwiększone bezpieczeństwo.

Przykłady:

public class Example {
    // final pole klasy
    private final String name;

    // final pole prymitywne
    private final int id;

    // final, ale może być referencją do różnych obiektów List, dopóki lista nie zostanie utworzona
    // po utworzeniu obiektu można zmienić referencję, ale nie samą referencję
    private final List<String> items;

    // Stała czasu kompilacji
    public static final double PI = 3.14159;

    public Example(String name, int id) {
        this.name = name; // przypisanie do pola final
        this.id = id;     // przypisanie do pola final
        this.items = new ArrayList<>(); // inicjalizacja pola final
    }

    // final metoda
    public final void printDetails() {
        System.out.println("Name: " + name + ", ID: " + id);
    }

    // metoda z parametrem final
    public void addItem(final String item) {
        // item = "nowy element"; // błąd kompilacji: nie można przypisać do zmiennej final
        items.add(item);
    }
}

// final klasa
// public final class ImmutableClass {
//     private final int value;
//
//     public ImmutableClass(int value) {
//         this.value = value;
//     }
//
//     public int getValue() {
//         return value;
//     }
// }

// public class SubclassOfImmutable extends ImmutableClass { // błąd kompilacji: nie można dziedziczyć po finalnej klasie
// }
```}}}}}```