Почему класс не может расширять перечисление?

Мне интересно, почему на языке Java a class не может расширить enum.

Я не говорю о enum, расширяющем enum (чего нельзя сделать, поскольку java не имеет множественного наследования и что enum неявно расширяет java.lang.Enum), но класс что extends an 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;
    }
}

Используется следующим образом:

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

Итак, может ли кто-нибудь дать обоснование (или указать мне на правый раздел JLS) для этого ограничения?

Ответ 1

Я думаю, что ответ на вопрос, почему они это сделали, исходит из этого вопроса:

В вашем примере, как бы вы создавали экземпляр MyClass? Перечисления никогда явно не создаются пользователем (через new MyEnum()) пользователем. Вы должны сделать что-то вроде MyClass.ASD, но не знаете, как это будет работать.

В принципе, я не знаю, какой синтаксис будет работать для вашего предлагаемого добавления. Вероятно, поэтому они сделали их окончательными и т.д....

EDIT ADDED

Если автор оригинального 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();
   }
}

Ответ 2

Вы не можете расширить enum. Они неявно final. Из JLS & sect; 8,9:

Тип перечисления неявно final, если он содержит хотя бы одну константу перечисления, которая имеет тело класса.

Кроме того, из JLS & sect; 8.1.4 - Суперклассы и подклассы:

Это ошибка времени компиляции, если ClassType называет класс enum или любой его вызов.

В основном enum представляет собой набор заданных констант. В связи с этим язык позволяет использовать перечисления в switch-cases. Например, разрешив их продление, они не будут иметь подходящий тип для коммутационных шкафов. Кроме того, экземпляр класса или другого перечисления, расширяющий перечисление, будет также являться экземпляром перечисления, которое вы расширяете. Это в основном нарушает цель enum.

Ответ 3

В древние времена pre 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;
    }

} 

В этой цифре есть две важные вещи:

  • частный конструктор, который не позволит создавать экземпляр класса снаружи
  • фактические значения "enum" хранятся в статических полях

Даже если это не окончательно, когда вы его расширите, вы поймете, что для компилятора требуется явный конструктор, который в свою очередь требует вызова супер-конструктора, что невозможно, поскольку он является закрытым. Другая проблема заключается в том, что статические поля в суперклассе по-прежнему хранят объект этого суперкласса, а не ваш расширяющий. Я думаю, что это может быть объяснением.

Ответ 4

Вся суть перечисления - создать замкнутый набор возможных значений. Это упрощает рассуждение о том, что такое тип этого перечисления - проще для вас программист, а также проще для компилятора (эта закрытость - это то, что позволяет эффективно обрабатывать перечисления в коммутаторах, например). Предоставление классу расширения перечисления откроет набор возможных значений; в этот момент, что enum купит вам, что обычный class не будет?

Ответ 5

Можно также добавить, что мы можем эмулировать Extensible enums с использованием интерфейсов.

Из блестящей книги Джошуа Блоха

http://books.google.com/books?id=ka2VUBqHiWkC&pg=PA165&lpg=PA165&dq=mulate+extensible+enums+with+interfaces&source=bl&ots=yYKhIho1R0&sig=vd6xgrOcKr4Xhb6JDAdkxLO278A&hl=en&sa=X&ei=XyBgUqLVD8-v4APE6YGABg&ved=0CDAQ6AEwAQ#v=onepage&q=mulate%20extensible%20enums%20with%20interfaces&f=false

или

http://jtechies.blogspot.com/2012/07/item-34-emulate-extensible-enums-with.html