In Java zijn init-blokken (initialization blocks) speciale codeblokken die worden uitgevoerd bij het aanmaken van een object van een klasse, maar voor de aanroep van de constructor. Er zijn twee soorten:
public class Example { static { System.out.println("Static block"); } { System.out.println("Instance block"); } public Example() { System.out.println("Constructor"); } }
Bij het aanmaken van een nieuw object zal de output zijn:
Static block
Instance block
Constructor
Het gebruik van init-blokken is zinvol wanneer er algemene logica voor alle constructors nodig is, of bij complexe initialisatie die niet in de variabele declaratie past. Maar in de meeste gevallen hebben constructors de voorkeur.
Vraag: In welke volgorde worden velden, static-blokken, instance-blokken en constructors geïnitialiseerd bij het aanmaken van een object?
Antwoord:
Verhaal
In een groot project ontstond er een probleem met initialisatie: een van de ontwikkelaars verplaatste de algemene logica van de constructor naar het init-blok, zonder rekening te houden met de volgorde van aanroep. Hierdoor werden sommige velden niet correct geïnitialiseerd voordat de logica werd uitgevoerd, wat leidde tot een NullPointerException tijdens het aanmaken van het object.
Verhaal
Herhaald gebruik van een groot init-blok in een abstracte klasse waarvan andere klassen afstamden, leidde ertoe dat subklassen de volgorde van initialisatie niet goed overschreven. Dit veroorzaakte onverwacht gedrag bij overerving en bugs gerelateerd aan de volgorde van aanroep van init-blokken en constructors.
Verhaal
Een ontwikkelaar veronderstelde dat static-velden opnieuw konden worden geïnitialiseerd bij elke nieuwe creatie van een object, en voegde logica voor het schoonmaken van middelen toe in het static-blok. Dit leidde ertoe dat de middelen slechts eenmaal werden schoongemaakt bij het laden van de klasse, terwijl al het volgende gezinsbeheer "vastliep". Aangezien het static-blok slechts één keer wordt aangeroepen, leidde dit tot geheugenlekken en onjuist middelenbeheer.