Почему инициализация констант перечисления Java не завершена?
я наткнулся на очень странный баг и я не могу объяснить, почему это происходит. Представьте себе следующее перечисление:
import java.awt.Color;
public class test {
/**
* @param args
*/
public static void main(String[] args) {
System.out.println(MyEnum.CONSTANT1.get());
System.out.println(MyEnum.CONSTANT2.get());
}
private enum MyEnum {
CONSTANT1(staticMethod1()),
CONSTANT2(staticMethod2());
private static final Color WHY_AM_I_NULL = new Color(255, 255, 255);
private final Color color;
private MyEnum(Color color) {
this.color = color;
}
public Color get() {
return color;
}
private static Color staticMethod1() {
return new Color(100, 100, 100);
}
private static Color staticMethod2() {
return WHY_AM_I_NULL;
}
}
}
результаты при запуске этого:
java.awt.Color[r=100,g=100,b=100]
null
вопрос в том, почему второй равен null?
поправка: Если вы помещаете WHY_AM_I_NULL в частный статический класс внутри перечисления, то он инициализируется первым.
4 ответов
проблема в том, что все статические поля (и экземпляры перечисления считаются таковыми) инициализируются в их объявленном порядке (спецификация). Так когда CONSTANT2
создается экземпляр, поле WHY_AM_I_NULL
по-прежнему не инициализируется (и, следовательно,null
).
поскольку вы не можете поместить поле перед экземплярами перечисления, вам нужно найти другой способ сделать то, что вы хотите (например, поместить поле вне класса перечисления). Если вы скажете нам, чего вы действительно хотите достичь, можно сделать дополнительные предложения.
Edit: если поставить WHY_AM_I_NULL
во вложенном классе поля этого класса будут инициализированы, как только класс будет впервые доступен (т. е. в этом случае во время выполнения staticMethod2
).
перечисления являются функцией компилятора. Фактически компилятор создает класс с именем MyEnum, который содержит 2 открытых статических поля CONSTANT1 и CONSTANT2 и другой код.
статическая инициализация выполняется вверх-вниз, поэтому КОНСТАНТА2 создается и инициализируется перед статической переменной WHY_AM_I_NULL. Вот почему WHY_AM_I_NULL имеет значение null при инициализации CONSTANT2.
WHY_AM_I_NULL
равно null, когда staticMethod2 вызывается-вот как JLS указывает инициализации
в другой последовательности вы получите 100, 255
вместо 100, null
:
private static final Color WHY_AM_I_NULL = new Color(255, 255, 255);
private enum MyEnum {
CONSTANT1(staticMethod1()),
CONSTANT2(staticMethod2());
//...
это происходит потому, что статические поля (включая значения перечисления) инициализируются в том порядке, в котором они появляются в файле.
так CONSTANT1
и CONSTANT2
быть инициализирована перед WHY_AM_I_NULL
, поэтому CONSTANT2
инициализируется с null
.