Блоки и порядок инициализации
Статический блок относится к классу, экземплярный — к каждому создаваемому объекту.
class Parent {
static int ps = log("parent static");
int pi = log("parent field");
{ log("parent instance block"); }
Parent() { log("parent constructor"); }
static int log(String value) {
System.out.println(value);
return 0;
}
}
class Child extends Parent {
static int cs = log("child static");
int ci = log("child field");
{ log("child instance block"); }
Child() { log("child constructor"); }
}При первом активном использовании new Child() порядок такой:
- инициализация класса
Parent: его статические поля и блоки в текстовом порядке; - инициализация класса
Child: его статические поля и блоки; - память объекта заполнена значениями по умолчанию;
- экземплярные поля и блоки
Parentв текстовом порядке; - тело конструктора
Parent; - экземплярные поля и блоки
Child; - тело конструктора
Child.
Компилятор фактически вставляет экземплярные инициализаторы в каждый конструктор после вызова родительского конструктора. Поэтому блок полезен для общей части нескольких конструкторов, но обычный приватный метод часто читается лучше.
Инициализация класса
Загрузка, linking и инициализация — разные этапы. Инициализацию обычно запускают new, вызов статического метода, чтение/запись неконстантного статического поля или reflection. JVM синхронизирует инициализацию класса.
Если static-инициализатор завершился с ошибкой, первый вызов получает ExceptionInInitializerError; следующие попытки обычно видят NoClassDefFoundError для ошибочного класса.
Ошибки
- опираться на значения полей, объявленных ниже, через косвенный вызов;
- вызывать переопределяемый метод из конструктора;
- выполнять сеть или тяжёлую работу в static-блоке;
- путать значение поля по умолчанию с явной инициализацией.
На собеседовании
Что раньше: поля или instance-блок? В том текстовом порядке, в котором они объявлены.
Когда выполняется static-блок? Один раз при инициализации класса данным загрузчиком.
Сначала родитель или наследник? На обоих уровнях сначала родитель.
Что получат поля до инициализаторов? Нулевые значения JVM: 0, false, null.
Связано: Исключения в блоке инициализации, Class loader, super java.