Почему класс не может расширять перечисление?
Мне интересно, почему на языке 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