为什么这个枚举编译?

Kev*_*ede 14 java enums

我想创建一个enum每个常量Map与之关联的位置.我完成了这个,给每个常量一个实例初始化器,如下所示:

import java.util.HashMap;
import java.util.Map;

public enum Derp {
    FOO {{
            mMap.put("bar", 1);
        }};

    // cannot be private
    protected final Map<String, Integer> mMap = new HashMap<>();
}
Run Code Online (Sandbox Code Playgroud)

我发现如果mMapprivate,则无法在实例初始化程序中引用它.错误是Cannot make a static reference to the non-static field mMap.在我发生这种情况之前,我咨询了JLS§8.9.2,其中部分说:

对于构造函数,实例初始化程序块或枚举常量的实例变量初始化程序表达式来说,它是一个编译时错误,它e指向e或向右侧声明的相同类型的枚举常量e.

我是不是通过FOOFOO自己的实例初始化器中隐式引用来打破这个规则?这是如何编译的?它不仅可以编译,而且可以在运行时正常工作.

(在我看来,这mMap不是private因为我隐式创建了一个匿名子类,它不能引用private其超类中的字段.由于枚举是隐含的,因此本身有点奇怪final......)

Rad*_*def 4

如果枚举常量的构造函数、实例初始值设定项块或实例变量初始值设定项表达式引用ee声明在 右侧的相同类型的枚举常量,则会出现编译时错误e

这里的规范只是意味着您不能按名称引用,因为 by 引用的字段e尚未初始化。这并不意味着您无法访问this.

它与任何其他初始化器的规则基本上相同(例如int x = x;

我们可以通过一个例子来了解为什么(Ideone):

enum Example {
    INSTANCE {{
        subversion();
    }};

    static void subversion() {
        System.out.println(INSTANCE);
    }

    public static void main(String[] args) {
        System.out.println(INSTANCE);
    }
}
Run Code Online (Sandbox Code Playgroud)

哪个输出

null
INSTANCE
Run Code Online (Sandbox Code Playgroud)

我发现如果mMap是私有的,则无法在实例初始值设定项中引用它。

您可以将调用限定为super.mMap.put(...);。privatemMap不能被继承,但可以从内部类访问。我在这里也介绍了这一点。它的缺点是简单的名称mMap引用了一个不存在的外部实例Derp

我们可以通过( Ideone )这样的例子来验证情况是否如此:

class Example {
    private int x;

    class Inner extends Example {{
        x = 1;       // refers to the outer instance
        super.x = 2; // refers to the inner instance
    }}

    public static void main(String[] args) {
        Example outer = new Example();
        Example inner = outer.new Inner();
        System.out.println(outer.x); // prints 1
        System.out.println(inner.x); // prints 2
    }
}
Run Code Online (Sandbox Code Playgroud)

除非你的情况FOO是静态的,所以没有外部实例 - 因此编译器错误。