CodeGym /Kursy /JAVA 25 SELF /Inicjalizacja pól statycznych i final

Inicjalizacja pól statycznych i final

JAVA 25 SELF
Poziom 15 , Lekcja 3
Dostępny

1. Pola statyczne: jak je inicjalizować?

Pole statyczne (static) nie należy do obiektu, lecz do całej klasy. Jego wartość istnieje w jednym, wspólnym egzemplarzu dla wszystkich obiektów tej klasy. Analogicznie — to jak ogłoszenie „wspólnej kasy” dla wszystkich pracowników firmy: nieważne, kto akurat przyszedł, kasa jest jedna dla wszystkich.

Inicjalizacja przy deklaracji

Najprostszy i najczęściej spotykany sposób inicjalizacji pola statycznego — przypisać mu wartość bezpośrednio przy deklaracji:

public class User {
    private static int userCount = 0; // inicjalizacja bezpośrednio tutaj

    // ... pozostały kod
}

Takie pole zostanie zainicjalizowane przy pierwszym załadowaniu klasy User do pamięci.

Inicjalizacja w bloku statycznym

Czasem potrzebna jest bardziej złożona logika inicjalizacji — na przykład wczytanie danych z pliku albo wykonanie obliczeń. W takim przypadku używa się statycznego bloku inicjalizacji:

public class Config {
    public static String configPath;

    static {
        // Ten blok wykona się DOKŁADNIE raz podczas ładowania klasy
        configPath = System.getenv("APP_CONFIG_PATH");
        if (configPath == null) {
            configPath = "/etc/app/default.conf";
        }
        System.out.println("Config path zainicjalizowana: " + configPath);
    }
}

Kiedy wykonywany jest blok statyczny?

  • Przy pierwszym odwołaniu do klasy (np. przy utworzeniu pierwszego obiektu lub wywołaniu dowolnej metody/pola statycznego).
  • Wykonuje się tylko raz dla każdej klasy.

Dostęp do pól statycznych — najważniejsze cechy

  • Do pól statycznych odwołujemy się przez nazwę klasy: User.userCount.
  • Można odwołać się także przez obiekt, ale to zły styl (wprowadza czytającego kod w błąd).

Przykład:

User u1 = new User();
User u2 = new User();
System.out.println(User.userCount); // poprawnie
System.out.println(u1.userCount);   // działa, ale nie jest zalecane!

2. Pola final: kiedy i jak je inicjalizować?

final — to modyfikator, który mówi: „To pole można przypisać tylko raz, a później nie można go zmienić”. Po inicjalizacji wartość pola staje się niezmienna: dla obiektu — to jego stała właściwość, a dla klasy (jeśli pole jest statyczne) — wspólna stała.

Przykłady użycia:

  • Stałe (np. PI).
  • Unikalny identyfikator obiektu, którego nie można zmienić po utworzeniu.

Wymagania dotyczące inicjalizacji pól final

W języku Java obowiązuje ścisła zasada: każde final-pole musi być zainicjalizowane albo przy deklaracji, albo w każdym konstruktorze klasy.

Inicjalizacja przy deklaracji

public class Circle {
    public static final double PI = 3.1415926535; // stała klasy
    private final String id = "CIRCLE";           // stała obiektu
}

Inicjalizacja w konstruktorze

Czasem wartość final-pola jest znana dopiero w momencie tworzenia obiektu:

public class User {
    private final int id;

    public User(int id) {
        this.id = id; // przypisujemy pole final w konstruktorze
    }
}

Ważne: jeśli klasa ma kilka konstruktorów, final-pole musi być zainicjalizowane w każdym z nich!

Przykład łączony

public class Token {
    private final String value;
    private final long timestamp;

    public Token(String value) {
        this.value = value;
        this.timestamp = System.currentTimeMillis();
    }
}

Błędy kompilacji przy nieprawidłowej inicjalizacji

Jeśli zapomnisz zainicjalizować final-pole, kompilator nie pozwoli zbudować programu:

public class Broken {
    private final int x; // nie został zainicjalizowany

    public Broken() {
        // x nie jest przypisywane!
    }
}
// Błąd: variable x might not have been initialized

3. Połączenie static i final: deklarowanie stałych klasy

Bardzo często spotyka się połączenie public static final. W języku Java tak deklaruje się stałe klasy — wartości, które ustala się raz i nie zmieniają się w czasie działania programu. Te stałe należą do całej klasy i są takie same dla wszystkich jej obiektów.

Składnia i przykład

public class MathUtils {
    public static final double PI = 3.1415926535;
    public static final String APP_NAME = "MyApp";
}

Wyjaśnienie:

  • public — dostępne wszędzie.
  • static — należy do całej klasy, a nie do pojedynczego obiektu.
  • final — nie można zmienić po inicjalizacji.

Użycie

double area = MathUtils.PI * r * r;
System.out.println(MathUtils.APP_NAME);

Konwencja: nazwy stałych zazwyczaj zapisuje się WIELKIMI_LITERAMI_Z_PODKREŚLENIEM.

4. Przykłady kodu: sposoby inicjalizacji pól statycznych i final

Przykład 1: Prosta klasa ze stałą

public class Constants {
    public static final int DAYS_IN_WEEK = 7;
    public static final String COMPANY = "Daisy LLC";
}

Przykład 2: Pole statyczne zainicjalizowane w bloku statycznym

public class AppConfig {
    public static final String DEFAULT_PATH;

    static {
        // Można wykonać złożoną logikę
        String env = System.getenv("APP_PATH");
        if (env != null) {
            DEFAULT_PATH = env;
        } else {
            DEFAULT_PATH = "/usr/local/app";
        }
    }
}

Przykład 3: pole final obiektu — inicjalizacja w konstruktorze

public class User {
    private static int nextId = 1;
    private final int id;
    private String name;

    public User(String name) {
        this.id = nextId++;
        this.name = name;
    }

    public int getId() { 
        return id; 
    }
    public String getName() {
        return name; 
    }
    public void setName(String name) { 
        this.name = name; 
    }
}

Użycie:

User u1 = new User("Ivan");
User u2 = new User("Maria");
System.out.println(u1.getId()); // 1
System.out.println(u2.getId()); // 2

Przykład 4: błąd przy nieprawidłowej inicjalizacji pola final

public class BadExample {
    private final int number;

    public BadExample() {
        // number nie został zainicjalizowany!
    }
}
// Błąd kompilacji: variable number might not have been initialized

5. Najlepsze praktyki pracy z polami static i final

Używaj public static final tylko dla prawdziwych stałych

Jeśli wartość może się zmienić w przyszłości (np. lista pracowników), nie oznaczaj jej jako final! Stałe muszą być naprawdę niezmienne.

public static final int MAX_USERS = 1000; // dobrze
public static final String[] USERS = new String[100]; // źle!

Chociaż sama referencja USERS się nie zmieni, zawartość tablicy można modyfikować. To może prowadzić do nieoczekiwanych błędów.

Do złożonej inicjalizacji używaj bloków statycznych

Jeśli stałej nie da się wyrazić prostym przypisaniem (np. wymaga obliczeń lub odczytu z pliku), użyj bloku statycznego.

Nie nadużywaj pól statycznych

Pola statyczne to globalne zmienne. Zbyt duża ich liczba może prowadzić do trudnych do wykrycia błędów i utrudniać utrzymanie kodu.

Nie rób obiektów zmiennych jako public static final

Jeśli obiekt jest zmienny, nie rób go publicznym i final. To otworzy wszystkim dostęp do jego wnętrza — ktoś na pewno z tego skorzysta.

6. Typowe błędy przy inicjalizacji pól statycznych i final

Błąd nr 1: niezainicjalizowane pole final. Jeśli zapomnisz zainicjalizować final-pole przy deklaracji albo we wszystkich konstruktorach, kompilator zgłosi błąd. Na przykład, jeśli klasa ma dwa konstruktory, a w jednym z nich zapomnisz przypisać wartość final-polu — pojawi się błąd.

Błąd nr 2: zmiana wartości pola final. Próba zmiany wartości final-pola po inicjalizacji skończy się błędem kompilacji.

public class Demo {
    private final int x = 5;
    public void change() {
        x = 10; // Błąd: cannot assign a value to final variable x
    }
}

Błąd nr 3: publiczne mutowalne pola static final. Jeśli zrobić zmienny obiekt (String[], int[] i in.) public static final, każdy kod będzie mógł zmieniać jego zawartość. To narusza enkapsulację i może prowadzić do trudnych do wykrycia błędów.

Błąd nr 4: używanie niestatycznych pól w bloku statycznym. W bloku statycznym nie można odwoływać się do pól niestatycznych, ponieważ nie są jeszcze zainicjalizowane (w tym momencie w ogóle nie istnieją).

Błąd nr 5: nieoczekiwana kolejność inicjalizacji. Jeśli w bloku statycznym odwołujesz się do pól statycznych zadeklarowanych dalej w kodzie, mogą one nie być jeszcze zainicjalizowane. Zawsze deklaruj pola statyczne przed blokami statycznymi, jeśli planujesz ich używać.

Komentarze
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION