为什么这个枚举代码是对静态字段的非法引用?

时间:2012-02-01 15:51:11

标签: java enums

此代码无法编译,因为存在对静态字段的非法引用。

public enum Foo {

  A,
  B;

  private Foo[] foos = new Foo[] { Foo.A };

}

您是否应该能够从非静态字段初始化程序访问静态字段?例如:

public class Foo {

  static int A;

  private int[] foos = new int[] { Foo.A };

}

编译好。

注意,在第一个示例中编译foos静态。

2 个答案:

答案 0 :(得分:17)

http://java.sun.com/docs/books/jls/third_edition/html/classes.html#8.9

查看Java语言规范,第三版,第8.9节
  

引用枚举类型的静态字段是编译时错误   这不是构造函数的编译时常量(第15.28节),   实例初始化程序块,或实例变量初始值设定项   该类型的表达。这是一个编译时错误   构造函数,实例初始化程序块或实例变量   枚举常量e的初始化表达式,用于引用自身或   一个在e。右侧声明的相同类型的枚举常量。

<强>讨论

  

如果没有这个规则,显然合理的代码会在运行时失败   由于枚举类型中固有的初始化循环性。 (一个   圆度存在于具有“自键型”静态字段的任何类中。)   以下是失败的代码类型示例:

enum Color {
        RED, GREEN, BLUE;
        static final Map<String,Color> colorMap = 
        new HashMap<String,Color>();
        Color() {
            colorMap.put(toString(), this);
        }
    } 
  

此枚举类型的静态初始化会抛出一个   NullPointerException,因为静态变量colorMap是   枚举常量的构造函数运行时未初始化。该   上面的限制确保这些代码不会编译。

答案 1 :(得分:7)

以大致相同,更简单的方式写出,更接近字节代码,我们看到:

public final class Foo {
    public static final Foo A = new Foo();
    public static final Foo B = new Foo();

    private Foo[] foos;

    private Foo() {
        this.foos = new Foo[] { Foo.A };
    }
}

您可以看到初始化A我们正在调用构造函数,该构造函数读取A。显然,虽然构造函数A仍然没有被初始化。

(事实证明,这个更简单的代码确实可以编译。它只是没有你所期望的那样。)

您可能需要Foo.values()而不是foos实例变量。