Вопрос-ответ

Can enums be subclassed to add new elements?

Можно ли разделить перечисления на подклассы для добавления новых элементов?

Я хочу взять существующее перечисление и добавить к нему дополнительные элементы следующим образом:

enum A {a,b,c}

enum B extends A {d}

/*B is {a,b,c,d}*/

Возможно ли это в Java?

Переведено автоматически
Ответ 1

Нет, вы не можете сделать это на Java. Помимо всего прочего, d тогда, по-видимому, это был бы экземпляр A (учитывая обычную идею "extends"), но пользователи, которые знали только о A, не знали бы об этом - что лишает смысла то, что enum является хорошо известным набором значений.

Если бы вы могли рассказать нам подробнее о том, как вы хотите использовать это, мы потенциально могли бы предложить альтернативные решения.

Ответ 2

Перечисления представляют собой полное перечисление возможных значений. Таким образом, (бесполезный) ответ - нет.

В качестве примера реальной проблемы возьмем будни, выходные дни и, при объединении, дни недели. Мы могли бы определить все дни внутри days-of-week, но тогда мы не смогли бы представлять свойства, характерные как для будних, так и для выходных дней.

Что мы могли бы сделать, так это иметь три типа перечислений с сопоставлением между буднями / выходными днями и днями недели.

public enum Weekday {
MON, TUE, WED, THU, FRI;
public DayOfWeek toDayOfWeek() { ... }
}
public enum WeekendDay {
SAT, SUN;
public DayOfWeek toDayOfWeek() { ... }
}
public enum DayOfWeek {
MON, TUE, WED, THU, FRI, SAT, SUN;
}

В качестве альтернативы у нас мог бы быть открытый интерфейс для определения дня недели:

interface Day {
...
}
public enum Weekday implements Day {
MON, TUE, WED, THU, FRI;
}
public enum WeekendDay implements Day {
SAT, SUN;
}

Или мы могли бы объединить два подхода:

interface Day {
...
}
public enum Weekday implements Day {
MON, TUE, WED, THU, FRI;
public DayOfWeek toDayOfWeek() { ... }
}
public enum WeekendDay implements Day {
SAT, SUN;
public DayOfWeek toDayOfWeek() { ... }
}
public enum DayOfWeek {
MON, TUE, WED, THU, FRI, SAT, SUN;
public Day toDay() { ... }
}
Ответ 3

Рекомендуемым решением для этого является расширяемый шаблон перечисления.

Это включает в себя создание интерфейса и использование его там, где вы в данный момент используете enum. Затем заставьте enum реализовать интерфейс. Вы можете добавить больше констант, добавив дополнительный enum / класс, который также расширяет интерфейс. Вот общая идея:

public interface TrafficLights {
public abstract String getColour();
}
public enum StandardTrafficLights implements TrafficLights {
RED, YELLOW, GREEN;
public String getColour() {
return name();
}
}
public enum WeirdTrafficLights implements TrafficLights {
DOUBLE_RED;
public String getColour() {
return name();
}
}

Обратите внимание, что если вы хотите что-то вроде TrafficLights.valueof(String) вам придется реализовать это самостоятельно.

Ответ 4

По сути, ваше перечисление - это обычный класс, сгенерированный компилятором. Этот сгенерированный класс расширяется java.lang.Enum. Техническая причина, по которой вы не можете расширить сгенерированный класс, заключается в том, что сгенерированный класс является final. Концептуальные причины, по которым это является окончательным, обсуждаются в этой теме. Но я добавлю механику к обсуждению.

Вот тестовое перечисление:

public enum TEST {  
ONE, TWO, THREE;
}

Результирующий код из javap:

public final class TEST extends java.lang.Enum<TEST> {
public static final TEST ONE;
public static final TEST TWO;
public static final TEST THREE;
static {};
public static TEST[] values();
public static TEST valueOf(java.lang.String);
}

Возможно, вы могли бы ввести этот класс самостоятельно и удалить "final". Но компилятор не позволяет вам расширять "java.lang.Enum" напрямую. Вы могли бы решить НЕ расширять java.lang.Enum , но тогда ваш класс и производные от него классы не были бы экземпляром java.lang.Enum ... что, возможно, на самом деле не имеет для вас никакого значения!

2023-05-15 19:15 java enums