Die Klasseninitialisierungsreihenfolge in Java (class initialization order) bestimmt, in welcher Reihenfolge Felder, Blöcke und Konstruktoren initialisiert werden. Kurz gesagt:
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() -> welche Reihenfolge?
Die Ausgabe wird sein:
Zuerst die statischen Blöcke der Eltern, dann die statischen Blöcke der Kinder, dann die nicht-statischen Blöcke und Konstruktoren in der Reihenfolge der Vererbung.
Frage: Wann genau werden die statischen Initialisierer in der Klasse ausgeführt:
class Ex {
static { System.out.println("static"); }
}
— bei der Erstellung der ersten Instanz oder bei der ersten Verwendung eines statischen Methoden/Felds?
Antwort: Der statische Initialisierer wird bei der ersten Zugriffs auf die Klasse ausgeführt, einschließlich des Zugriffs auf jedes statische Mitglied (Methode/Feld), und nicht nur bei der Erstellung einer Instanz.
Geschichte
In einer Bankenapplikation wurde statischer Verbindungs-Pool im statischen Block initialisiert, aber aufgrund des Zugriffs auf eine statische Methode vor der Erstellung der ersten Instanz war noch keine Verbindung erstellt worden. Das führte zu NullPointerException unter Last.
Geschichte
Der Logging-Service hing von einem nicht-statischen Feld ab, das nach dem Aufruf des Konstruktors der Elternklasse initialisiert wurde. Protokolle wurden in den null-Logger geschrieben, und wichtige Fehlermeldungen gingen verloren.
Geschichte
Als ein neues Feld mit einem Standardwert hinzugefügt wurde, platzierte der Entwickler es nach dem Initialisierungsblock: der Block versuchte, auf ein noch nicht initialisiertes Feld zuzugreifen, was während des Starts der Anwendung zu Fehlern und einer schwierigen Fehlersuche führte.