我想知道为什么,尽管在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
,因此不具备这些领域,但信息理论上应该可以在编译时,它可以很容易地验证运行一个小测试
// 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
也是编译器为基本枚举类生成静态枚举值的方式,Test
如下所示VALUE3
:所有成员都是类型Test
,具体类型被丢弃.
但是,在我看来,如果编译器只是保留这些类型
public static final Test$1 Test.VALUE1 public static final Test$2 Test.VALUE2 public static final Test Test.VALUE3
所有周围的代码仍然有效.此外,我们还可以做什么,我最初尝试并获得CONST_RELATED_TO_VALUE1
通过Test.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
这甚至为调试提供了额外的好处,即内部子类名称清楚地映射到相应的枚举值.
现在我明白了必须进行一些细微的改动,但是从匿名到命名的类而不是丢弃这些类似乎是一个很小的改变,这看起来很不错,没有一个简单的方法来使用重写来模拟它成员或什么的.
所以我想知道为什么除了时间之外没有像这样实现?我是否遗漏了一些关键的东西,这会阻止编译器这样做(关于实现复杂性或类型系统不可能)是否只是为了保持简单而没有实现,因为这些行没有时间或东西?
(我主要是寻找为什么决定从编译器/类型系统的角度来实现它的原因,而不是实际的替代方案,因为肯定有一对,尽管它似乎仍然是一个很好的模式)
静态成员如是CONST_RELATED_TO_VALUE1
相应枚举值的匿名类的成员,但不是枚举类本身的成员.与其他匿名类一样,VALUE1
这里的对象被声明为类型,Test
即使它是匿名子类的实例Test
.
因此,您无法访问CONST_RELATED_TO_VALUE1
via VALUE1.CONST_RELATED_TO_VALUE1
因为VALUE1
是类型的引用,Test
并且CONST_RELATED_TO_VALUE1
是匿名子类的成员但不是Test
.CONST_RELATED_TO_VALUE1
只能由匿名类的其他成员访问.
如果要访问匿名类中定义的值,则VALUE1
需要m()
在枚举对象的匿名类中重写枚举类型的方法(例如),并以某种方式返回或提供所需的值暴露(通过VALUE1.m()
).