为什么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 

问题是,为什么第二个是空的?

修改:如果你把WHY_AM_I_NULL放在枚举中的私有静态类中,那么它首先被初始化。

问题是所有静态字段(和枚举实例都这样计算)都按其声明的顺序( 规范 )进行初始化。 因此,当实例化CONSTANT2时,字段WHY_AM_I_NULL仍未初始化(因此为null )。

由于您无法在枚举实例之前放置该字段,因此您必须找到其他方法来执行您想要的操作(例如,将该字段放在枚举类之外)。 如果你告诉我们,你真正想要实现的目标,可以提出进一步的建议。

编辑:如果将WHY_AM_I_NULL放在嵌套类中,则只要首次访问类(即,在执行staticMethod2期间),就会初始化此类的字段。

枚举是编译器function。 实际上编译器创建了名为MyEnum的类,它包含2个公共静态字段CONSTANT1和CONSTANT2以及其他代码。

静态初始化是从上到下完成的,因此创建CONSTANT2并在静态变量WHY_AM_I_NULL之前初始化。 这就是为什么在初始化CONSTANT2时WHY_AM_I_NULL为空的原因。

调用WHY_AM_I_NULL时, WHY_AM_I_NULL为null – 这是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()); //... 

这是因为静态字段(包括枚举值)按它们在文件中出现的顺序初始化。

因此CONSTANT1CONSTANT2WHY_AM_I_NULL之前初始化,因此CONSTANT2初始化为null