Порядок инициализации класса в Java (class initialization order) определяет, в какой последовательности инициализируются поля, блоки и конструкторы. Кратко:
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() -> какой порядок?
Вывод будет:
Сначала статик-блоки родителей, потом статик-блоки детей, потом нестатик-блоки и конструкторы в порядке наследования.
Вопрос: Когда именно будут выполнены статические инициализаторы в классе:
class Ex {
static { System.out.println("static"); }
}
— при создании первого экземпляра или при первом применении любого статического метода/поля?
Ответ: Статический инициализатор выполняется при первом доступе к классу, включая доступ к любому статическому члену (методу/полю), а не только при создании экземпляра.
История
В банковском приложении статический пул соединений инициализировался в статик-блоке, но из-за обращения к статическому методу до создания первого экземпляра соединения еще не было создано. Это привело к NullPointerException при запуске под нагрузкой.
История
Служба логирования зависела от нестатического поля, которое инициализировалось после вызова конструктора родительского класса. Журналы записывались в null-логгер, и были утеряны важные сообщения об ошибках.
История
При добавлении нового поля с начальным значением разработчик поместил его после блока инициализации: блок пытался использовать еще не инициализированное поле, что приводило к ошибкам во время старта приложения и сложному поиску причины.