此代码无法编译,因为存在对静态字段的非法引用。
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
静态。
答案 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
实例变量。