2

考虑以下枚举类:

public enum APlanet {
    VENUS   ()  {public void stuff(){}},
    EARTH   () {public void stuff(){}},
    MARS    ()  {public void stuff(){}};
    public abstract void stuff();
}

public enum BPlanet {
    VENUS   (),
    EARTH   (),
    MARS    ();
}

然后APlanet.MARS.getClass().isEnum()返回 false 而BPlanet.MARS.getClass().isEnum()返回 true。为什么?请注意,APlanet.getDeclaringClass().isEnum()正确返回 true。

具体来说,我正在尝试可靠地测试对象是否为枚举:

Object a = APlanet.MARS;
Object b = BPlanet.MARS;
a.getClass().isEnum() /* returns false */
b.getClass().isEnum() /* returns true  */

然而

Enum.class.isAssignableFrom(a.getClass()); /* returns true */

内部类 APlanet.MARS 不是 Enum 有点令人困惑,但您可以将其分配给 Enum,如下所示:

Enum<?> m = APlanet.MARS;
4

1 回答 1

8

JLS 第 8.9.1 节 - 枚举常量

枚举常量的可选类主体隐式定义了一个匿名类声明(第 15.9.5 节),该声明扩展了直接封闭的枚举类型。类主体由匿名类的通常规则管理;特别是它不能包含任何构造函数。

您已在第一个枚举中声明了特定于常量的类主体:

 MARS ()  {public void stuff(){}}; // The curly braces defines a class body

这将创建一个匿名类。因此,MARS.getClass()将返回这个匿名类的 Class 实例,它不是Enum.


这类似于您创建接口的匿名子类的实例,或者像这样的任何其他类:

SomeInterface obj = new SomeInterface() { /** Method definitions **/ };

然后obj.getClass()不会返回SomeInterface,但是,ClassContainingThatDeclaration$1

请注意,APlanet.getDeclaringClass().isEnum()正确返回 true

我怀疑应该是 - APlanet.MARS.getDeclaringClass().isEnum()。根据Enum#getDeclaringClass()方法的文档,这将返回 true:

返回与此枚举常量的枚举类型对应的 Class 对象。两个枚举常量 e1 和 e2 是相同的枚举类型当且仅当e1.getDeclaringClass() == e2.getDeclaringClass()。(此方法返回的值可能与Object.getClass()具有特定于常量的类主体的枚举常量的方法返回的值不同。)


但我认为枚举不能被子类化?

现在可以想到的疑问是,enum不能被子类化。那么,如何创建 enum 的匿名子类呢?它如何扩展enum?这是因为,枚举是最终的,除非它声明一些特定于常量的类主体,根据JLS 第 8.9 节 - 枚举

枚举类型是隐式最终的,除非它包含至少一个具有类主体的枚举常量。

您仍然不能显式扩展enum

即使特定于常量的类体隐式地创建了一个匿名子类,你也不能显式地扩展一个enum. 根据JLS 第 8.1.4 节 - 超类和子类

如果 ClassType 命名类 Enum 或对它的任何调用,则这是一个编译时错误。

于 2013-09-14T19:42:35.820 回答