为什么Java允许引用枚举成员的枚举成员?

19

给定以下枚举类型:

enum Repeat {
    Daily,
    Weekly,
    Yearly
}

我意识到我们可以这样写:

Repeat repeat = Repeat.Daily.Weekly.Yearly.Weekly;

等价于:

Repeat repeat = Repeat.Weekly;

我可以知道为什么允许这种语法吗?有没有办法让编译器警告我们避免这种情况?


有没有一种方法可以让编译器警告我们避免这种情况?你应该为此配置Linter - deathangel908
如果字段是static:则对Primary表达式进行求值,并且结果被丢弃。 [...] 字段访问表达式的结果是在Primary表达式类型的类或接口中指定的类变量的值。 - Radiodef
4个回答

19

由于Daily,Weekly,Yearly枚举中的静态字段,并持有Repeat对象,所以这是允许的。此外,编译器会发出警告"The static field Repeat.Weekly should be accessed in a static way"。这类似于下面的代码行。

class Foo{
    public static Foo obj1 = new Foo();
    public static Foo obj2 = new Foo();
    public static Foo obj3 = new Foo();
}

Foo f = Foo.obj1.obj2.obj3; // will work fine but you will get a warning from the compiler.

这是Repeat枚举类型的字节码检查的部分,从中可以明确得知Enum变量是static的,并且保存了枚举对象本身。

   0: new           #1                  // class com/java8/demo/Repeat
   3: dup
   4: ldc           #14                 // String Daily
   6: iconst_0
   7: invokespecial #15                 // Method "<init>":(Ljava/lang/String;I)V
  10: putstatic     #19                 // Field Daily:Lcom/java8/demo/Repeat;
  13: new           #1                  // class com/java8/demo/Repeat 

5

枚举实例只是枚举类的静态实例。

我们有两种方式访问一个类的静态字段:

  1. 通过类本身:Repeat.Daily
  2. 通过类的实例:Repeat.Daily.Daily

当你链式调用你的枚举时:

Repeat repeat = Repeat.Daily.Weekly.Yearly.Weekly;

这就像从类的实例中获取一个静态字段一样。

2
有没有一种方法可以让编译器警告我们避免这种情况发生?
是的,使用一个好的集成开发环境(IDE),并打开警告功能。这样,你在编写代码时就会被通知,甚至在编译之前就能发现问题。
例如,在Eclipse中,它被称为“非静态访问静态成员”。

enter image description here


1
枚举字面量是静态成员,对于每个静态成员,可以使用类引用来访问它们:
TypeName.staticMember
TypeName.staticMethod()

或者在一个实例上:

new TypeName().staticMember
new TypeName().staticMethod()

第二种方法不被鼓励使用(编译器会发出警告)。
由于枚举字面量只是静态成员,Repeat.Daily.Weekly.Yearly.Weekly 就像上面的第二段代码片段一样,在实例引用上访问静态成员。
对于一个类,可以这样做:
class Type {
    static Type INSTANCE1, INSTANCE2, INSTANCE3;
}

可以使用Type.INSTANCE1.INSTANCE2.INSTANCE3来引用INSTANCE3。这是有效的,但不是好的实践。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接