下面的代码段,
public enum Main {
INSTANCE;
private final static String STR = "abc";
private final Map<Integer, Character> map = new HashMap<>();
private final static int[] NUMS = { 1, 2, 3 };
private Main() {
for (int i = 0; i < STR.length(); i++)
map.put(NUMS[i], STR.charAt(i)); // compiler error!
}
public char toChar(int i) {
return map.get(i);
}
public static void main(String[] args) {
System.out.println(Main.INSTANCE.toChar(2));
}
}
它产生了下面的编译错误,
illegal reference to static field NUMS from initializer.
为什么STR
允许static
但NUMS
不允许?{1}}
答案 0 :(得分:3)
从构造函数,实例初始值设定项或枚举类型的实例变量初始化表达式引用枚举类型的
static
字段是编译时错误,除非该字段是常量变量(§4.12。 4)。
我认为限制是因为枚举常量(即INSTANCE
)是在类初始化期间创建的(在幕后它是static final
字段),这可能引用静态{ {1}}在构造函数中仍然是NUMS
,这可能会导致异常。这可以通过用正常类替换null
并运行代码来复制。
答案 1 :(得分:3)
在所有其他字段之前初始化枚举实例,因此您无法初始化static
这样的字段。
但是有一个简单的解决方法!
private static class Holder {
final static int[] NUMS = { 1, 2, 3 };
}
private Main() {
for (int i = 0; i < STR.length(); i++)
map.put(Holder.NUMS[i], STR.charAt(i)); // No compiler error!
}
这是Initialization-on-demand holder idiom的一个示例,它利用内部类在类本身初始化之前完全初始化的事实,这是由JLS保证是线程安全的。