programowanieProgramista Java Middle/Senior

Co to jest kolejność inicjalizacji klas w Javie, jak działa i do czego może prowadzić błędne zrozumienie kolejności inicjalizacji członów statycznych i niestatycznych?

Zdaj rozmowy kwalifikacyjne z asystentem AI Hintsage

Odpowiedź.

Kolejność inicjalizacji klasy w Javie (class initialization order) definiuje, w jakiej sekwencji inicjalizowane są pola, bloki i konstruktory. W skrócie:

  1. Pola statyczne i inicjalizatory statyczne są wykonywane w kolejności ich pojawienia się w klasie, gdy klasa jest ładowana przez JVM (raz na klasę).
  2. Pola niestatyczne i inicjalizatory są wykonywane w kolejności ich pojawienia się KAŻDĄ raz przy tworzeniu instancji, przed wywołaniem konstruktora.
  3. Konstruktor jest wykonywany po inicjalizacji wszystkich pól i bloków.

Przykład

class Parent { static { System.out.println("Parent static"); } { System.out.println("Parent init"); } Parent() { System.out.println("Parent constructor"); } } class Child extends Parent { static { System.out.println("Child static"); } { System.out.println("Child init"); } Child() { System.out.println("Child constructor"); } } // new Child() -> jaka kolejność?

Wynik będzie:

  1. Parent static
  2. Child static
  3. Parent init
  4. Parent constructor
  5. Child init
  6. Child constructor

Najpierw bloki statyczne rodziców, potem bloki statyczne dzieci, następnie bloki niestatyczne i konstruktory w kolejności dziedziczenia.

Pytanie podchwytliwe.

Pytanie: Kiedy dokładnie zostaną wykonane inicjalizatory statyczne w klasie:

class Ex {
    static { System.out.println("static"); }
}

— przy tworzeniu pierwszej instancji czy przy pierwszym użyciu dowolnej metody/pola statycznego?

Odpowiedź: Inicjalizator statyczny jest wykonywany przy pierwszym dostępie do klasy, w tym przy dostępie do dowolnego członu statycznego (metody/pola), a nie tylko przy tworzeniu instancji.

Przykłady rzeczywistych błędów z powodu braku znajomości szczegółów tematu.


Historia

W aplikacji bankowej statyczna pula połączeń była inicjalizowana w bloku statycznym, ale z powodu odwołania się do metody statycznej przed utworzeniem pierwszej instancji połączenia jeszcze nie stworzono. Doprowadziło to do NullPointerException podczas uruchamiania pod obciążeniem.


Historia

Usługa logowania zależała od niestatycznego pola, które było inicjalizowane po wywołaniu konstruktora klasy bazowej. Logi były zapisywane w null-loggerze, a ważne komunikaty o błędach zostały utracone.


Historia

Podczas dodawania nowego pola z wartością początkową, deweloper umieścił je po bloku inicjalizacji: blok próbował użyć jeszcze nie zainicjalizowanego pola, co prowadziło do błędów podczas startu aplikacji i trudności w znalezieniu przyczyny.