Are fields initialized before constructor code is run in Java?
Инициализируются ли поля перед запуском кода конструктора в Java?
Кто-нибудь может объяснить результат следующей программы? Я думал, конструкторы инициализируются перед переменными экземпляра. Поэтому я ожидал, что результат будет "XZYY".
classX { Yb=newY();
X() { System.out.print("X"); } }
classY { Y() { System.out.print("Y"); } }
publicclassZextendsX { Yy=newY();
Z() { System.out.print("Z"); }
publicstaticvoidmain(String[] args) { newZ(); } }
Переведено автоматически
Ответ 1
Правильный порядок инициализации таков:
Инициализаторы статических переменных и блоки статической инициализации в текстовом порядке, если класс не был инициализирован ранее.
Вызов super() в конструкторе, явный или неявный.
Инициализаторы переменных экземпляра и блоки инициализации экземпляра в текстовом порядке.
Если вы посмотрите на декомпилированную версию файла класса
classX { Y b;
X() { b = newY(); System.out.print("X"); } }
classY { Y() { System.out.print("Y"); } }
publicclassZextendsX {
Y y;
Z() { y = newY(); System.out.print("Z"); }
publicstaticvoidmain(String args[]) { newZ(); } }
Вы можете обнаружить, что переменная экземпляра y перемещается внутри конструктора, поэтому последовательность выполнения следующая
Вызовите конструктор Z
Это запускает конструктор по умолчанию для X
Вызывается первая строка X конструктора new Y().
Напечатать Y
Печать X
Вызовите первую строку в constructor Z new Y()
С принтами Y
Печать Z
Все переменные экземпляра инициализируются с помощью инструкций конструктора.
Ответ 3
Когда вы вызываете конструктор, инициализаторы переменных экземпляра запускаются перед телом конструктора. Как вы думаете, какой результат дает приведенная ниже программа?
Метод main вызывает конструктор Tester, который выдает исключение. Можно ожидать, что предложение catch перехватит это исключение и выведет перехваченное исключение. Но если вы попытались запустить его, вы обнаружили, что он ничего подобного не делает, и выдает StackOverflowError.
Ответ 4
Чтобы прояснить неправильные представления о static, я просто обращусь к этому небольшому фрагменту кода:
Обратите внимание, что у нас есть static {} который вызывается после двух экземпляров {}. это происходит потому, что мы запускаем конструктор в середине, меняя порядок выполнения при первом вызове конструктора.
При первой инициализации объекта инициализируйте текущий объект как для статической, так и для инициализации экземпляра, чередуя их в зависимости от порядка появления
Для всех следующих инициализаций выполняйте инициализацию экземпляра только в порядке появления, поскольку статическая инициализация уже произошла.
Мне нужно исследовать, как сочетание наследования и явных и неявных вызовов super повлияет на это, и я обновлю результаты. Скорее всего, это будет похоже на другие предоставленные ответы, за исключением того, что они ошиблись со статической инициализацией.