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

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

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 для более подробной информации.

Другие вопросы по тегам