Kolejność inicjalizacji klasy w Javie (class initialization order) definiuje, w jakiej sekwencji inicjalizowane są pola, bloki i konstruktory. W skrócie:
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:
Najpierw bloki statyczne rodziców, potem bloki statyczne dzieci, następnie bloki niestatyczne i konstruktory w kolejności dziedziczenia.
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.
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.