Я был очень сбит с толку, когда обнаружил, что инициализация полей в Java имеет какой-то странный порядок. Пример кода, когда результат init() перезаписывается инициализацией поля:
public abstract class Parent {
public String parentField = "dupa";
public Parent(){
init(); // uhh, bad practice to call abstract method in a super constructor
}
protected abstract void init();
}
public class Child extends Parent {
public String childField = null; // assigning null is unnecessary, another bad practice
@Override
protected void init(){
childField = "initialized";
System.out.println("After init(): " + childField);
}
}
...
Child child = new Child(); // OUTPUT: After init(): initialized
System.out.println("After all: " + child.childField); // OUTPUT: After all: null
Я узнал, каков порядок выполнения при вызове new Child();
:
- Инициализация родительских полей, но childField уже существует и имеет значение по умолчанию (childField = null)
- Parent constructor
- overridden init() called by parent constructor (childField = "initialized")
- Инициализация дочерних полей: childField = null (снова)
- Детский конструктор
Я знаю, что этот пример полон плохих практик. Однако интуитивный порядок для меня был бы таким: инициализация полей (от родителей к дочерним), затем конструкторы (от родителей к дочерним).
Какова цель такого порядка инициализации? Почему инициализаторы полей не выполняются до их потенциального первого использования? Если поле еще не инициализировано, то почему его разрешено использовать?
childField
вChild
до завершения ctor дляParent
? - person Boris the Spider   schedule 28.01.2017super
будет полностью сконструировано. - person 4castle   schedule 28.01.2017