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

Скажите, что у вас есть этот фрагмент кода

private final Set set = new HashSet() {{ add(1); }};


SomeConstructor() {
   printSet();
}

long printSet() {
    new Thread(() -> {System.out.println(set)}).start();
}

например, если компилятор решил сделать это похожим на

private final Set set;
SomeConstructor() {
   printSet();
   set = new HashSet() {{ add(1); }};
}

это было бы проблемой, потому что calculateWaitTime() создает новый поток, который может видеть набор как нулевой или не иметь в нем 1.

Итак, еще раз вопрос, возможно ли это переупорядочение? Или все окончательные поля, инициализированные вне конструктора, инициализируются перед конструктором или, по крайней мере, всегда перемещаются компилятором в верхнюю часть конструктора.


person katiex7    schedule 07.02.2018    source источник
comment
прежде чем вы запустите конструктор, экземпляр, которому они принадлежат, не существует. также: вызов не окончательного (может быть изменен путем наследования) метода из конструктора - не самая умная вещь.   -  person Stultuske    schedule 07.02.2018


Ответы (1)


Это невозможно для final полей.

Просто взгляните на Спецификация языка Java® Java SE 8 Edition › 17.5.2 Чтение окончательных полей во время построения:

17.5.2 Чтение последних полей во время строительства

Чтение конечного поля объекта в потоке, создающем этот объект, упорядочено относительно инициализации этого поля в конструкторе по обычным правилам «происходит до». Если чтение происходит после того, как поле установлено в конструкторе, он видит значение, присвоенное последнему полю, в противном случае он видит значение по умолчанию.

Но, как вы также можете видеть, это не гарантируется для последующих модификаций final полей с использованием отражения. Дополнительные сведения см. в разделе 17.5.3.

person CroWell    schedule 07.02.2018