Конечные поля, инициализированные вне конструкторов, инициализируются перед запуском конструктора?
Скажем, у вас есть этот фрагмент кода
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); }};
}
это было бы проблемой, потому что возбуждающая функция CalcuWaitTime() создает новый поток, который может видеть набор как нулевой или не имеющий 1 в нем.
Итак, вопрос снова, возможно ли это изменение порядка? Или же все конечные поля, инициализированные вне конструктора, инициализируются перед конструктором или, по крайней мере, всегда перемещаются компилятором в верхнюю часть конструктора
1 ответ
Это не возможно для final
поля.
Достаточно взглянуть на Спецификацию языка Java ® Java SE 8 Edition > 17.5.2 Чтение окончательных полей во время создания:
17.5.2. Чтение последних полей во время строительства
Чтение конечного поля объекта в потоке, который создает этот объект, упорядочено относительно инициализации этого поля в конструкторе по обычным правилам "происходит до". Если чтение происходит после того, как поле установлено в конструкторе, он видит значение, назначенное последнему полю, в противном случае он видит значение по умолчанию.
Но, как вы также можете видеть, это не гарантируется для последующих final
полевые модификации с использованием отражения. См. 17.5.3 для более подробной информации.