我想采取一个现有的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中可行吗?
当前回答
我建议你采取另一种方式。
与其扩展现有的枚举,不如创建一个更大的枚举,并创建它的一个子集。 例如,如果你有一个叫PET的枚举,你想把它扩展到ANIMAL,你应该这样做:
public enum ANIMAL {
WOLF,CAT, DOG
}
EnumSet<ANIMAL> pets = EnumSet.of(ANIMAL.CAT, ANIMAL.DOG);
注意,pets不是一个不可变的集合,您可能会使用Guava或Java9来提高安全性。
其他回答
我的编码方式如下:
// enum A { a, b, c }
static final Set<Short> enumA = new LinkedHashSet<>(Arrays.asList(new Short[]{'a','b','c'}));
// enum B extends A { d }
static final Set<Short> enumB = new LinkedHashSet<>(enumA);
static {
enumB.add((short) 'd');
// If you have to add more elements:
// enumB.addAll(Arrays.asList(new Short[]{ 'e', 'f', 'g', '♯', '♭' }));
}
LinkedHashSet既提供了每个条目只存在一次,又提供了它们的顺序保留。如果顺序无关紧要,则可以使用HashSet。以下代码在Java中是不可行的:
for (A a : B.values()) { // enum B extends A { d }
switch (a) {
case a:
case b:
case c:
System.out.println("Value is: " + a.toString());
break;
default:
throw new IllegalStateException("This should never happen.");
}
}
代码可以这样写:
for (Short a : enumB) {
switch (a) {
case 'a':
case 'b':
case 'c':
System.out.println("Value is: " + new String(Character.toChars(a)));
break;
default:
throw new IllegalStateException("This should never happen.");
}
}
从Java 7开始,你甚至可以用String做同样的事情:
// enum A { BACKWARDS, FOREWARDS, STANDING }
static final Set<String> enumA = new LinkedHashSet<>(Arrays.asList(new String[] {
"BACKWARDS", "FOREWARDS", "STANDING" }));
// enum B extends A { JUMP }
static final Set<String> enumB = new LinkedHashSet<>(enumA);
static {
enumB.add("JUMP");
}
使用enum替换:
for (String a : enumB) {
switch (a) {
case "BACKWARDS":
case "FOREWARDS":
case "STANDING":
System.out.println("Value is: " + a);
break;
default:
throw new IllegalStateException("This should never happen.");
}
}
为了帮助理解为什么在语言实现级别上扩展Enum是不合理的,请考虑如果将扩展Enum的实例传递给只理解基本Enum的例程会发生什么。编译器承诺覆盖所有情况的开关实际上并不覆盖那些扩展的Enum值。
这进一步强调了Java Enum的值不是像C那样的整数,例如:要使用Java Enum作为数组索引,你必须显式地要求它的ordinal()成员,要给Java Enum一个任意的整数值,你必须为它添加一个显式的字段并引用命名的成员。
这不是对OP的愿望的评论,只是关于为什么Java永远不会做到这一点。
不,在Java中不能这样做。除此之外,d可能是A的一个实例(考虑到“extends”的正常思想),但只知道A的用户不会知道它——这就违背了枚举是一组已知值的观点。
如果你能告诉我们更多关于你想如何使用它,我们可能会建议其他解决方案。
基于@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:
}
实际上,ENUM只是编译器生成的一个常规类。生成的类扩展了java.lang.Enum。不能扩展生成的类的技术原因是生成的类是最终的。在这个主题中讨论了它是最终的概念原因。但我将在讨论中加入机制。
下面是一个测试枚举:
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”。直接枚举”。你可以决定不扩展java.lang。Enum,但是这样你的类和它的派生类就不会是java.lang.Enum…这对你来说可能并不重要!