2011-08-25 98 views
9

我偶然发现了一个非常奇怪的错误,我无法解释它为什么会发生。想象一下以下枚举:为什么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 

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

Ammendment: 如果你把WHY_AM_I_NULL在一个私人静态类枚举内,那么它首先被初始化。

+0

Ammended新的观测 –

+1

另外,如果您尝试直接使用常量,而不是通过方法,Eclipse显示错误。使用静态方法时情况并非如此。即使FindBugs不会显示问题!我认为这至少应该是一个警告 –

回答

12

问题是,所有静态字段(和枚举实例都是这样计数的)按其声明的顺序进行初始化(specification)。因此,当CONSTANT2被实例化时,字段WHY_AM_I_NULL仍未初始化(因此也为null)。因为你不能把这个字段放在枚举实例之前,你必须找到一些你想做的事情的其他方式(例如,把这个字段放在enum类之外)。如果你告诉我们,你真正想要完成什么,可以提出进一步的建议。

编辑:如果你把WHY_AM_I_NULL在嵌套类,这个类的字段将尽快类是第一次访问初始化(即,在staticMethod2执行过程中这种情况下)。

+0

我只是想有一个常数,用于枚举常量的初始化。当我将常量放入枚举中的私有静态类时它工作。 这个Enum的用户不关心这个内部常量,我不想让它声明不止一次(或者创建多次,如果你有它创建颜色的方法) –

+1

在这种情况下我确实使用静态嵌套类作为字段持有者类。 –

4

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

静态初始化是从上到下进行的,所以CONSTANT2被创建并在静态变量WHY_AM_I_NULL之前被初始化。这就是当CONSTANT2被初始化时WHY_AM_I_NULL为空的原因。

1

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

所以CONSTANT1CONSTANT2WHY_AM_I_NULL之前得到初始化,因此CONSTANT2null初始化。

2

WHY_AM_I_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()); 
    //... 
+0

-1。它甚至没有回答为什么一个字段没有在枚举内初始化,而是通过显示它如何在枚举之外工作来转移问题。另一点需要注意的是,**它从来不是一个正确的答案,因为这是因为它是如何指定的。“**请参见[如何回答](http://softwareengineering.stackexchange.com/help/how-to-回答) –