Синтаксис инициализации полей экземпляра — это специальный блок кода, заключённый в фигурные скобки внутри класса, но вне методов и конструкторов. Такой блок называется instance initializer block. Он выполняется каждый раз при создании нового объекта класса, непосредственно после вызова конструктора родительского класса и до выполнения кода конструктора текущего класса.
public class Example { { // Instance initializer block System.out.println("Инициализация экземпляра"); } private int x; public Example(int x) { this.x = x; System.out.println("Конструктор"); } }
Instance initializer полезен для:
Что будет, если в классе существуют и instance initializer, и конструктор? В каком порядке они выполняются?
Ответ: Сначала выполняется instance initializer, затем код конструктора. Если в классе есть несколько instance initializer-блоков, они выполняются в том порядке, в котором описаны.
Пример:
public class Demo { { System.out.println("Instance initializer 1"); } public Demo() { System.out.println("Constructor"); } { System.out.println("Instance initializer 2"); } } // Output при new Demo(): // Instance initializer 1 // Instance initializer 2 // Constructor
История
На одном проекте разработчик разместил логику в instance initializer вместо метода или конструктора. При унаследовании класса и переопределении конструктора instance initializer всё равно выполнился, что привело к неожиданному порядку инициализации и ошибкам в бизнес-логике.
История
В другом проекте instance initializer обращался к полям класса, которые были инициализированы ниже по коду. Оказалось, что переменные ещё не были инициализированы, и возникло NullPointerException при создании объекта.
История
Команда добавила в instance initializer операцию, связанную с внешними ресурсами (БД). В связи с этим каждый вызов конструктора делал соединение к БД, что перегрузило систему при пакетном создании объектов.