Java: инициализированное встроенное закрытое конечное поле имеет значение null

Я не могу понять, почему закрытая переменная имеет значение null, даже если она инициализирована inline. Вот фрагмент моего кода:

public abstract class A {
    public A() {
        initialize();
    }

    protected abstract void initializeLayout();
    protected void initialize() {
        // Do something
        initializeLayout();
    }
}

public abstract class B extends A {
    private final Object myVariable = new Object();

    @Override
    protected void initializeLayout() {
        // Do something with myVariable
    }
}

Ну, когда этот код достигнет B.initailizeLayout, myVariable имеет значение NULL. Я думал, что встроенное поле было инициализировано перед всем остальным, даже до конструктора. Я что-то не так справлюсь?

Ответ 1

Конструктор суперкласса A (который вызывает initialize(), который вызывает B initializeLayout()), выполняется до того, как инициализируются переменные экземпляра подкласса B. Поэтому ваша переменная экземпляра myVariable по умолчанию остается пустой.

Ответ 2

Конструктор (возможно неявный) дочернего элемента B будет выполнять следующие действия:

  • все поля обнулены (null, 0, 0.0, false)
  • вызов конструктора супер A
    • вызов B.initializeLayout со всеми полями null
  • инициализировать все поля, которые назначены в их объявлении
  • вызов остальной части конструктора

То, что вы пытаетесь делать, очень сильно подвержено ошибкам в java. Многие шашки стиля отмечают этот код как плохой стиль (вызов не конечного метода в конструкторе).

Вы можете сделать

private /*final*/ Object myVariable; // Must not be initialized!

@Override
protected void initializeLayout() {
    myVariable = new Object();
    // Do something with myVariable
}

После инициализации myVariable инициализируется myVariable после вызова initializeLayout.

Лучше избегать.