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

时间:2013-10-17 17:28:06

标签: java inheritance syntax enums jls

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

我不是在讨论扩展enum的{​​{1}}(由于java没有多重继承而且enum隐式扩展enum。 {1}}),但是java.lang.Enumextends的类只是为了添加额外的方法,而不是额外的枚举值。

类似的东西:

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

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

5 个答案:

答案 0 :(得分:11)

您无法扩展enum。它们是隐含的final。来自JLS § 8.9

  

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

此外,来自JLS §8.1.4 - Superclasses and Subclasses

  

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

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

答案 1 :(得分: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;
    }

} 

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

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

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

答案 2 :(得分:4)

枚举的重点是创建一个已关闭的可能值集。这样可以更容易地推断出枚举类型的值是什么 - 对于程序员来说更容易,对编译器来说也更容易(例如,这种封闭性可以让它在交换机中有效地处理枚举)。允许类扩展枚举将打开一组可能的值;那时,enum会给你一个普通的class不会带来什么?

答案 3 :(得分:2)

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

在您的示例中,您将如何实例化MyClass?用户永远不会明确地实例化枚举(通过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();
   }
}

答案 4 :(得分:1)