为什么无法从Java中的专用枚举值访问静态final成员 [英] Why can't I access static final members from a dedicated enum value in Java

查看:311
本文介绍了为什么无法从Java中的专用枚举值访问静态final成员的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想知道为什么,虽然在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;
}

访问常量。 VALUE1.CONST_RELATED_TO_VALUE1 无效。



现在我明白了, VALUE1 VALUE2 等实际上通常被视为类型 Test 的静态最终实例,因此没有这些字段,但是信息理论上应在编译时可用,可以轻松验证运行小测试

  //打印类型和静态成员
for(Object o:Test.values()){
System.out.println(o.toString :+ o.getClass());
for(字段字段: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 code> VALUE2 。但是它也看起来像我们失去关于 VALUE1 VALUE2 的具体类型信息的原因是编译器生成 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 ,这显然是一个实例的类型测试$ 1 而不仅仅是测试,虽然应该通常避免,在这种情况下看起来很好通过实例访问该静态成员。



现在正如许多人正确指出的,左侧使用匿名类不是有效的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 类型,即使它是因此,您不能访问 CONST_RELATED_TO_VALUE1


的匿名子类。由于 VALUE1 是类型的引用 c c VALUE1.CONST_RELATED_TO_VALUE1 code>和 CONST_RELATED_TO_VALUE1 是匿名子类的成员,但不是 Test 的成员。 CONST_RELATED_TO_VALUE1 只能由匿名类的其他成员访问。



如果要访问 VALUE1 的匿名类,您需要有一个枚举类型的方法(例如 m()覆盖枚举对象的匿名类,并且以某种方式返回或提供您要公开的值(通过 VALUE1.m())。


I was wondering why, while it's perfectly valid to do the following in 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;
}

accessing the constants as one would expect using Test.VALUE1.CONST_RELATED_TO_VALUE1 does not work.

Now I understand, VALUE1, VALUE2 etc. are actually all generally seen as static final instance of type Test and hence don't have those fields, but the information should theoretically available at compile time, which can easily be verified running a 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);
            }
        }             
     }

which results in the following output

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

It's clear that we actually have proper dedicated sub-classes at runtime for VALUE1 and VALUE2. But it also looks like the reason we lose the concrete type information about VALUE1 and VALUE2 is the way the compiler generates the static enum values for the base enum class Test as used by VALUE3: All members are of type Test and the concrete types are discarded.

However, it seems to me that if the compiler simply kept those types like so

        public static final Test$1 Test.VALUE1                                                                                                                                    
        public static final Test$2 Test.VALUE2                                                                                                                                    
        public static final Test Test.VALUE3                                                                                                                                    

all surrounding code would still work. In addition we could also do what I tried initially and access CONST_RELATED_TO_VALUE1 through Test.VALUE1, which is now clearly an instance of type Test$1 and not just Test and while it should be generally avoided, it seems in this case perfectly fine to access that static member through an instance.

Now as many people correctly pointed out, using anonymous classes to the left is not valid Java code and probably also for the compiler not allowed without some major specification change. However, this could easily be solved by using named inner classes, so we would have

        public static final Test.Value1 Test.VALUE1                                                                                                                                    
        public static final Test.Value2 Test.VALUE2                                                                                                                                    
        public static final Test Test.VALUE3                                                                                                                                    

This even provides an added benefit for debugging that the inner sub class name clearly maps to the corresponding enum value.

Now I understand there would have to be some minor changes, but going from anonymous to named classes and not throwing away the types seems like a small change and this looks like quite a nice feature to have, without an easy way to emulate it using overridden members or something.

So I was wondering why this wasn't implemented like this except time? Am I missing something crucial here that would prevent the compiler from doing this (either regarding implementation complexity or type system impossibilities) was it just not implemented to keep it simpler, because there was no time or something along those lines?

(I'm mainly looking for reasons why it was decided to implement it like this from a compiler/typesystem point of view, not for practical alternatives to this, as there are definitely a couple, though it still seems like a nice pattern to have)

解决方案

Static members such as CONST_RELATED_TO_VALUE1 are members of the anonymous class for the corresponding enum value, but not members of the enum class itself. As with other anonymous classes, the object VALUE1 here is declared as being of type Test even though it's an instance of the anonymous subclass of Test.

Therefore, you can't access CONST_RELATED_TO_VALUE1 via VALUE1.CONST_RELATED_TO_VALUE1 because VALUE1 is a reference of type Test and CONST_RELATED_TO_VALUE1 is a member of the anonymous subclass but not of Test. CONST_RELATED_TO_VALUE1 can only be accessed by other members of the anonymous class.

If you want to access values defined in the anonymous class for VALUE1, you need to have a method (say, m()) of the enum type that you override in the anonymous class for the enum object, and that returns or provides somehow the value that you want to expose (via VALUE1.m()).

这篇关于为什么无法从Java中的专用枚举值访问静态final成员的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆