为什么这个枚举编译?
Why does this enum compile?
我想创建一个 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<>();
}
我发现如果mMap
是private
,它不能在实例初始化器中被引用。错误是 Cannot make a static reference to the non-static field mMap
。在我想到这个原因之前,我咨询了JLS §8.9.2,其中部分说:
It is a compile-time error for the constructors, instance initializer blocks, or instance variable initializer expressions of an enum constant e
to refer to e
or to an enum constant of the same type that is declared to the right of e
.
我在 FOO
自己的实例初始化器中隐式引用 FOO
是不是违反了这条规则?这是如何编译的?它不仅可以编译,而且可以在运行时正常工作。
(我想到 mMap
不能是 private
因为我隐式创建了一个匿名子类,它不能引用其超类中的 private
字段。这有点本身很奇怪,因为枚举是隐式的 final
...)
It is a compile-time error for the constructors, instance initializer blocks, or instance variable initializer expressions of an enum constant e
to refer to e
or to an enum constant of the same type that is declared to the right of e
.
这里的说明只是表示不能通过name引用,因为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);
}
}
输出
null
INSTANCE
I found that if mMap
is private, it cannot be referenced in the instance initializer.
您可以将呼叫限定为 super.mMap.put(...);
。私有 mMap
不被继承,但可以从内部 class 访问。 。简而言之,简单名称 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
}
}
除了你的情况 FOO
是静态的,所以没有外部实例——因此编译器错误。
这是因为 FOO
是它自己的 Derp
的匿名子类 - 在创建 FOO
时它已经存在。
public class Enums {
public enum Derp {
FOO {{
mMap.put("bar", 1);
}};
// cannot be private
protected final Map<String, Integer> mMap = new HashMap<>();
}
public static void main(String[] args) {
System.out.println(Derp.class);
System.out.println(Derp.FOO.getClass());
}
}
class Enums$Derp
class Enums$Derp
我想创建一个 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<>();
}
我发现如果mMap
是private
,它不能在实例初始化器中被引用。错误是 Cannot make a static reference to the non-static field mMap
。在我想到这个原因之前,我咨询了JLS §8.9.2,其中部分说:
It is a compile-time error for the constructors, instance initializer blocks, or instance variable initializer expressions of an enum constant
e
to refer toe
or to an enum constant of the same type that is declared to the right ofe
.
我在 FOO
自己的实例初始化器中隐式引用 FOO
是不是违反了这条规则?这是如何编译的?它不仅可以编译,而且可以在运行时正常工作。
(我想到 mMap
不能是 private
因为我隐式创建了一个匿名子类,它不能引用其超类中的 private
字段。这有点本身很奇怪,因为枚举是隐式的 final
...)
It is a compile-time error for the constructors, instance initializer blocks, or instance variable initializer expressions of an enum constant
e
to refer toe
or to an enum constant of the same type that is declared to the right ofe
.
这里的说明只是表示不能通过name引用,因为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);
}
}
输出
null
INSTANCE
I found that if
mMap
is private, it cannot be referenced in the instance initializer.
您可以将呼叫限定为 super.mMap.put(...);
。私有 mMap
不被继承,但可以从内部 class 访问。 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
}
}
除了你的情况 FOO
是静态的,所以没有外部实例——因此编译器错误。
这是因为 FOO
是它自己的 Derp
的匿名子类 - 在创建 FOO
时它已经存在。
public class Enums {
public enum Derp {
FOO {{
mMap.put("bar", 1);
}};
// cannot be private
protected final Map<String, Integer> mMap = new HashMap<>();
}
public static void main(String[] args) {
System.out.println(Derp.class);
System.out.println(Derp.FOO.getClass());
}
}
class Enums$Derp
class Enums$Derp