我想采取一个现有的enum,并添加更多的元素,如下所示:
enum A {a,b,c}
enum B extends A {d}
/*B is {a,b,c,d}*/
这在Java中可行吗?
我想采取一个现有的enum,并添加更多的元素,如下所示:
enum A {a,b,c}
enum B extends A {d}
/*B is {a,b,c,d}*/
这在Java中可行吗?
当前回答
基于@Tom Hawtin - tackline的回答,我们增加了开关支持,
interface Day<T> {
...
T valueOf();
}
public enum Weekday implements Day<Weekday> {
MON, TUE, WED, THU, FRI;
Weekday valueOf(){
return valueOf(name());
}
}
public enum WeekendDay implements Day<WeekendDay> {
SAT, SUN;
WeekendDay valueOf(){
return valueOf(name());
}
}
Day<Weekday> wds = Weekday.MON;
Day<WeekendDay> wends = WeekendDay.SUN;
switch(wds.valueOf()){
case MON:
case TUE:
case WED:
case THU:
case FRI:
}
switch(wends.valueOf()){
case SAT:
case SUN:
}
其他回答
我建议你采取另一种方式。
与其扩展现有的枚举,不如创建一个更大的枚举,并创建它的一个子集。 例如,如果你有一个叫PET的枚举,你想把它扩展到ANIMAL,你应该这样做:
public enum ANIMAL {
WOLF,CAT, DOG
}
EnumSet<ANIMAL> pets = EnumSet.of(ANIMAL.CAT, ANIMAL.DOG);
注意,pets不是一个不可变的集合,您可能会使用Guava或Java9来提高安全性。
对此,推荐的解决方案是可扩展枚举模式。
这涉及到创建一个接口,并在当前使用枚举的位置使用该接口。然后使枚举实现接口。通过添加扩展接口的附加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)这样的东西,你必须自己实现它。
为了帮助理解为什么在语言实现级别上扩展Enum是不合理的,请考虑如果将扩展Enum的实例传递给只理解基本Enum的例程会发生什么。编译器承诺覆盖所有情况的开关实际上并不覆盖那些扩展的Enum值。
这进一步强调了Java Enum的值不是像C那样的整数,例如:要使用Java Enum作为数组索引,你必须显式地要求它的ordinal()成员,要给Java Enum一个任意的整数值,你必须为它添加一个显式的字段并引用命名的成员。
这不是对OP的愿望的评论,只是关于为什么Java永远不会做到这一点。
枚举表示可能值的完整枚举。所以(毫无帮助的)答案是否定的。
举一个实际问题的例子,工作日,周末,工会,一周的天数。我们可以在“天-周”中定义所有的天,但这样就不能表示“工作日”和“周末-天”的特殊属性。
我们可以做的是,有三种枚举类型,并在weekdays/weekend-days和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;
}
或者,我们可以为day-of-week提供一个开放式接口:
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() { ... }
}
我倾向于避免枚举,因为它们是不可扩展的。继续以OP为例,如果A在库中,而B在您自己的代码中,则如果A是枚举,则不能扩展A。这是我有时替换枚举的方法:
// access like enum: A.a
public class A {
public static final A a = new A();
public static final A b = new A();
public static final A c = new A();
/*
* In case you need to identify your constant
* in different JVMs, you need an id. This is the case if
* your object is transfered between
* different JVM instances (eg. save/load, or network).
* Also, switch statements don't work with
* Objects, but work with int.
*/
public static int maxId=0;
public int id = maxId++;
public int getId() { return id; }
}
public class B extends A {
/*
* good: you can do like
* A x = getYourEnumFromSomeWhere();
* if(x instanceof B) ...;
* to identify which enum x
* is of.
*/
public static final A d = new A();
}
public class C extends A {
/* Good: e.getId() != d.getId()
* Bad: in different JVMs, C and B
* might be initialized in different order,
* resulting in different IDs.
* Workaround: use a fixed int, or hash code.
*/
public static final A e = new A();
public int getId() { return -32489132; };
}
有一些陷阱要避免,请参阅代码中的注释。根据您的需要,这是枚举的可靠、可扩展的替代方案。