【发布时间】:2015-12-18 03:13:29
【问题描述】:
我想知道为什么,虽然在 Java 中执行以下操作是完全有效的
public enum Test {
VALUE1() {
public static final String CONST_RELATED_TO_VALUE1 = "constant";
public static final String OTHER_CONST_RELATED_TO_VALUE1 = "constant";
},
VALUE2() {
public static final String CONST_RELATED_TO_VALUE2 = "constant";
},
VALUE3;
}
使用Test.VALUE1.CONST_RELATED_TO_VALUE1 访问常量不起作用。
现在我明白了,VALUE1、VALUE2 等实际上通常都被视为Test 类型的静态最终实例,因此没有这些字段,但理论上这些信息应该在编译时可用,这可以通过little test 轻松验证
// print types and static members
for (Object o: Test.values()) {
System.out.println(o.toString() + ": " + o.getClass());
for (Field field : o.getClass().getDeclaredFields()) {
if (java.lang.reflect.Modifier.isStatic(field.getModifiers())) {
System.out.println("\t" + field);
}
}
}
导致以下输出
VALUE1: class Test$1
public static final java.lang.String Test$1.CONST_RELATED_TO_VALUE1
public static final java.lang.String Test$1.OTHER_CONST_RELATED_TO_VALUE1
VALUE2: class Test$2
public static final java.lang.String Test$2.CONST_RELATED_TO_VALUE2
VALUE3: class Test
public static final Test Test.VALUE1
public static final Test Test.VALUE2
public static final Test Test.VALUE3
private static final Test[] Test.$VALUES
很明显,我们实际上在运行时为VALUE1 和VALUE2 提供了适当的专用子类。但看起来我们丢失有关VALUE1 和VALUE2 的具体类型信息的原因也是编译器为VALUE3 使用的基枚举类Test 生成静态枚举值的方式:所有成员都属于输入Test 并丢弃具体类型。
但是,在我看来,如果编译器只是像这样保留这些类型
public static final Test$1 Test.VALUE1
public static final Test$2 Test.VALUE2
public static final Test Test.VALUE3
所有周围的代码仍然可以工作。此外,我们还可以执行我最初尝试的操作并通过Test.VALUE1 访问CONST_RELATED_TO_VALUE1,这显然是Test$1 类型的实例,而不仅仅是Test,虽然通常应该避免它,但似乎在这种情况下通过实例访问该静态成员非常好。
现在正如许多人正确指出的那样,在左侧使用匿名类不是有效的 Java 代码,而且如果没有一些重大的规范更改,编译器也可能不允许使用。但是,这可以通过使用命名内部类轻松解决,因此我们将拥有
public static final Test.Value1 Test.VALUE1
public static final Test.Value2 Test.VALUE2
public static final Test Test.VALUE3
这甚至为调试提供了一个额外的好处,即内部子类名称清楚地映射到相应的枚举值。
现在我知道必须进行一些小的更改,但是从匿名类到命名类并且不丢弃类型似乎是一个很小的更改,这看起来是一个相当不错的功能,没有简单的方法来模拟它使用覆盖的成员或其他东西。
所以我想知道为什么除了时间之外没有这样实现?我是否在这里遗漏了一些重要的东西,会阻止编译器执行此操作(无论是关于实现复杂性还是类型系统的不可能性),是否只是没有实现它以使其更简单,因为没有时间或类似的东西?
(我主要是在寻找为什么决定从编译器/类型系统的角度来实现它的原因,而不是实际的替代方案,因为肯定有几个,尽管它看起来仍然不错模式)
【问题讨论】:
-
您可能想阅读this。
-
@SotiriosDelimanolis:是的,我明白你的意思,所以我们通常不能有匿名类的成员作为程序员,我猜这扩展到编译器,不能有任何匿名类字段等。(这是本质上也是@Pshemo 写的)但是如果那是它崩溃的地方,请将其设为命名类
Test.Value1,它应该可以再次工作。
标签: java types enums compiler-construction