为什么一个类不能扩展枚举?

Una*_*ivi 13 java syntax inheritance enums jls

我想知道为什么在Java语言class中无法扩展enum.

我不是在谈论一个enum延伸的enum(这不能做,因为Java没有多重继承,而enumŠ隐含延长java.lang.Enum),但一类extends的enum以只添加额外的方法,而不是额外的枚举值.

就像是:

enum MyEnum
{
    ASD(5),
    QWE(3),
    ZXC(7);
    private int number;
    private asd(int number)
    {
        this.number=number;
    }
    public int myMethod()
    {
        return this.number;
    }
}

class MyClass extends MyEnum
{
    public int anotherMethod()
    {
        return this.myMethod()+1;
    }
}
Run Code Online (Sandbox Code Playgroud)

要像这样使用:

System.out.println(MyClass.ASD.anotherMethod());
Run Code Online (Sandbox Code Playgroud)

那么,任何人都可以为此限制提供理由(或指向正确的JLS部分)吗?

Roh*_*ain 11

你无法扩展enum.他们含蓄地说final.来自JLS§8.9:

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

此外,来自JLS§8.1.4 - 超类和子类:

如果ClassType为类命名Enum或对其进行任何调用,则为编译时错误.

基本上,a enum是一组枚举的预定义常量.因此,该语言允许您使用枚举switch-cases.例如,通过允许扩展它们,不会使它们成为开关案例的合格类型.除此之外,扩展枚举的类或其他枚举的实例也将是您扩展的枚举的实例.这enum基本上打破了s 的目的.

  • @LuiggiMendoza当然可以,否则就会编译.规范为什么这么说?在编写JLS时,他们并没有随意选择,大多数(如果不是全部)决策都有充分的理由; 这就是为什么我要求背后的理由. (2认同)
  • @LuiggiMendoza 抱歉,他已经收到了两个很好的理由,而不是意见,说明为什么事情是这样设计的。这是上帝(即高斯林)在创造宇宙时没有选择的情况。(谷歌爱因斯坦的原始报价) (2认同)

mac*_*ias 7

在Java 1.5之前的古代,你可能会做这样的枚举:

public class MyEnum {

public static final MyEnum ASD = new MyEnum(5);
public static final MyEnum QWE = new MyEnum(3);
public static final MyEnum ZXC = new MyEnum(7);

private int number;

private MyEnum(int number) {
    this.number = number;
}

public int myMethod() {
    return this.number;
    }

} 
Run Code Online (Sandbox Code Playgroud)

这个数字有两个重要的事情:

  • 私有构造函数,不允许从外部实例化该类
  • 实际的"枚举"值存储在静态字段中

即使它不是最终的,当你扩展它时,你会发现编译器需要一个显式的构造函数,反过来需要调用超级构造函数,这是不可能的,因为那个是私有的.另一个问题是超类中的静态字段仍然存储超类的对象而不是扩展类的对象.我认为这可能是一个解释.


ysh*_*vit 5

枚举的全部要点是创建一组可能的值的封闭集。这使得更容易推断出该枚举类型的值是什么——对于程序员来说更容易,对于编译器来说也更容易(例如,这种封闭性使得它可以在开关中有效地处理枚举)。允许类扩展枚举将打开可能值的集合;到那时,enum你会得到什么是常客class不会买的东西?


use*_*300 3

我认为他们为什么这样做的答案来自这个问题:

在您的示例中,您将如何实例化 MyClass?枚举永远不会new MyEnum()由用户显式实例化(通过 a )。你必须做类似的事情MyClass.ASD,但不确定它是如何工作的。

基本上,我不知道什么语法适用于您提议的添加。这可能就是为什么他们把它们定为最终版本等等......

编辑添加

如果原始 Enum 的作者提前计划(不太可能),并且您不太担心线程安全,您可以这样做:(顺便说一句,我可能会对任何在生产代码中实际执行此操作的人尖叫,YMMV )

public enum ExtendibleEnum {

   FOO, BAR, ZXC;

   private Runnable anotherMethodRunme;  // exact Interface will vary, I picked an easy one
                           // this is what gets "injected" by your other class

   public void setAnotherMethodRunMe(Runnable r) {  // inject here
      anotherMethodRunme= r;
   }

   public void anotherMethod() {  // and this behavior gets changed
      anotherMethodRunme.run();
   }
}
Run Code Online (Sandbox Code Playgroud)