Enum初始化程序

时间:2017-03-10 07:28:02

标签: java enums

下面的代码段,

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允许staticNUMS不允许?{1}}

2 个答案:

答案 0 :(得分:3)

根据language specification

,不允许这样做
  

从构造函数,实例初始值设定项或枚举类型的实例变量初始化表达式引用枚举类型的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保证是线程安全的。