De initialisatievolgorde van een klasse in Java (class initialization order) bepaalt in welke volgorde velden, blokken en constructeurs worden geïnitialiseerd. Kort samengevat:
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() -> wat is de volgorde?
De uitvoer zal zijn:
Eerst de statische blokken van de ouders, dan de statische blokken van de kinderen, dan de niet-statische blokken en constructeurs in de volgorde van overerving.
Vraag: Wanneer zullen de statische initializers in de klasse worden uitgevoerd:
class Ex {
static { System.out.println("static"); }
}
— bij het maken van het eerste exemplaar of bij de eerste toegang tot een statische methode/veld?
Antwoord: De statische initializer wordt uitgevoerd bij de eerste toegang tot de klasse, inclusief toegang tot elk statisch lid (methode/veld), en niet alleen bij het maken van een instantie.
Verhaal
In een bankapplicatie werd een statische verbindingspool geïnitialiseerd in een statisch blok, maar vanwege de aanroep van een statische methode vóór de creatie van de eerste instantie, was de verbinding nog niet gemaakt. Dit leidde tot een NullPointerException onder belasting.
Verhaal
De loggingdienst was afhankelijk van een niet-statisch veld dat werd geïnitialiseerd na de aanroep van de constructeur van de bovenliggende klasse. Logs werden geschreven naar een null-logger, waardoor belangrijke foutmeldingen verloren gingen.
Verhaal
Bij het toevoegen van een nieuw veld met een beginwaarde plaatste de ontwikkelaar het na de initialisatieblok: het blok probeerde een nog niet geïnitialiseerd veld te gebruiken, wat leidde tot fouten tijdens de opstart van de applicatie en een moeilijke zoektocht naar de oorzaak.