15

我想知道为什么在 Java 语言中 aclass不能扩展enum.

我不是在谈论enum扩展 an enum(这是无法完成的,因为 java 没有多重继承,并且enum隐式地 extend java.lang.Enum),而是一个类extendsanenum仅添加额外的方法,而不是额外的枚举值.

就像是:

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;
    }
}

像这样使用:

System.out.println(MyClass.ASD.anotherMethod());

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

4

6 回答 6

12

您不能扩展enum. 他们是含蓄的final。从JLS § 8.9

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

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

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

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

于 2013-10-17T17:29:35.060 回答
8

在 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;
    }

} 

这个图有两点很重要:

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

即使扩展它时它不是最终的,您也会意识到编译器需要一个显式构造函数,而反过来又需要调用超级构造函数,这是不可能的,因为它是私有的。另一个问题是超类中的静态字段仍然存储该超类的对象,而不是您的扩展对象。我认为这可以作为一种解释。

于 2013-10-17T18:02:02.430 回答
5

枚举的全部意义在于创建一组封闭的可能值。这使得推断该枚举类型的值是什么变得更容易——对程序员来说更容易,对编译器来说也更容易(例如,这种封闭性使它能够在开关中有效地处理枚举)。允许一个类扩展一个枚举将打开一组可能的值;到那时,普通人不会enum买给你什么?class

于 2013-10-17T17:46:38.733 回答
3

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

在您的示例中,您将如何实例化 MyClass?枚举永远不会被用户显式实例化(通过 a new MyEnum())。你必须做一些类似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();
   }
}
于 2013-10-17T17:35:47.573 回答
1

枚举的全部意义在于创建一组封闭的可能值。这使得更容易推断该枚举类型的值是什么,因此常量集仍将保持封闭和未扩展,但枚举将再次携带扩展类提供的额外方法。

于 2021-09-06T17:44:15.523 回答