Инициализируются ли поля перед кодом конструктора на Java?

Может ли кто-нибудь объяснить вывод следующей программы? Я думал, что конструкторы инициализируются перед переменными экземпляра. Поэтому я ожидал, что выход будет "XZYY".

class X {
    Y b = new Y();

    X() {
        System.out.print("X");
    }
}

class Y {
    Y() {
        System.out.print("Y");
    }
}

public class Z extends X {
    Y y = new Y();

    Z() {
        System.out.print("Z");
    }

    public static void main(String[] args) {
        new Z();
    }
}

Ответ 1

Правильный порядок инициализации:

  • Статические инициализаторы инициализации и статические блоки инициализации в текстовом порядке, если класс ранее не был инициализирован.
  • вызов super() в конструкторе, явный или неявный.
  • Инициализаторы переменных экземпляра и блоки инициализации экземпляра в текстовом порядке.
  • Оставшееся тело конструктора после super().

См. разделы §2.17.5-6 спецификации виртуальной машины Java.

Ответ 2

Если вы посмотрите на декомпилированную версию файла класса

class X {
    Y b;

    X() {
        b = new Y();
        System.out.print("X");
    }
}

class Y {
    Y() {
        System.out.print("Y");
    }
}

public class Z extends X {

    Y y;

    Z() {
        y = new Y();
        System.out.print("Z");
    }

    public static void main(String args[]) {
        new Z();
    }
}

Вы можете обнаружить, что переменная экземпляра y перемещается внутри конструктора, поэтому последовательность выполнения выглядит следующим образом

  • Вызов конструктора Z
  • Он запускает конструктор по умолчанию X
  • Вызывается первая строка конструктора X new Y().
  • Печать Y
  • Печать X
  • Вызов первой строки в конструкторе Z new Y()
  • Печать y
  • Печать Z

Все переменные экземпляра инициализируются с помощью инструкций конструктора.

Ответ 3

Порядок инициализации выглядит следующим образом:

  • Статические переменные и блоки инициализации в порядке их появления
  • Вызов super() в теле конструктора
  • Переменные экземпляра и блоки инициализации в порядке их появления
  • Остальная часть тела конструктора

Из раздела §12.5 в спецификации виртуальной машины Java.

Ответ 4

Последовательность инициализации задана в JLS 12.5:

1. Сначала выделяется память для нового объекта

2. Затем все переменные экземпляра в объекте (включая те, которые определены в этом классе и все его суперклассы) инициализируются значениями по умолчанию

3. Наконец, вызывается конструктор.

fooobar.com/info/78207/...