[英]Generic Enum with generic type Enum
我有以下接口和类定义。
interface A
{
}
class B
{
public static enum C implements A
{
c1, c2, c3;
}
public static enum D implements A
{
d1, d2, d3;
}
public static enum E implements A
{
e1, e2, e3;
}
}
现在我有一个类,我声明一个Map并将枚举作为键并设置一个值。
class Test
{
private Map<C, String> myMap;
public void assignVal()
{
myMap = new EnumMap<C, String>(C.class);
myMap.put(C.c1, String.valueOf(1));
}
}
问题 :如您所见,myMap与枚举C绑定。我想创建myMap的通用版本,因此我可以在B类中分配任何枚举值。
我已经通过stackoverflow帖子: 如何使用泛型实现枚举?
你不能用EnumMap
做到这一点。
EnumMap需要一个单一类型的键 - 构造函数通过将泛型类型绑定到具体类型来强制执行此操作。
在引擎盖下,它构建了一个可能的键值缓存,用于强制运行时类型安全。
如果要允许层次结构中的键,则需要使用其他类型的映射。
尝试这个:
private Map<Enum<? extends A>, String> myMap;
这将类型绑定到任何实现A的Enum。
这相当于<? extends Enum<?> & A>
<? extends Enum<?> & A>
,但更容易输入。
我会说teppic所说的 - 你不能将EnumMap
一般用于A
所有子类。 它必须用特定的具体类构建。 请参阅EnumMap的JavaDoc
https://docs.oracle.com/javase/7/docs/api/java/util/EnumMap.html
我看到你似乎有两种选择
使用其他类型的Map实现(例如HashMap
)
Map<A, String> myMap1 = new HashMap<>();
myMap1.put(C.c1, C.c1.name());
System.out.println(myMap1);
输出将是:
{c1=c1}
实现A
另一个子类,以便您可以使用EnumMap
如果由于某些原因,您确实想要使用EnumMap
, 并且您不希望将C
, D
, E
所有值都实现为一个枚举,那么您仍然可以使用以下解决方案。
实现A
的新子类(在下面的代码示例中称之为SuperCde
),它具有C
, D
和E
所有可能值,并且它有一个静态方法getSuperCde()
作为桥接器:
public static enum SuperCde implements A{
c1,c2,c3,
d1,d2,d3,
e1,e2,e3
;
public static SuperCde getSuperCde(A a) {
if (a instanceof C) {
C cValue = (C) a;
switch (cValue) {
case c1: return SuperCde.c1;
case c2: return SuperCde.c2;
case c3: return SuperCde.c3;
default: throw new IllegalArgumentException();
}
} else if (a instanceof D) {
D dValue = (D) a;
switch (dValue) {
case d1: return SuperCde.d1;
case d2: return SuperCde.d2;
case d3: return SuperCde.d3;
default: throw new IllegalArgumentException();
}
} else if (a instanceof E) {
E eValue = (E) a;
switch (eValue) {
case e1: return SuperCde.e1;
case e2: return SuperCde.e2;
case e3: return SuperCde.e3;
default: throw new IllegalArgumentException();
}
} else {
throw new IllegalArgumentException();
}
}
}
然后您可以使用以下代码:
Map<SuperCde, String> myMap2 = new EnumMap<SuperCde, String>(SuperCde.class);
myMap2.put(SuperCde.getSuperCde(C.c1), C.c1.name());
System.out.println(myMap2);
输出将是:
{c1=c1}
正如其他人所指出的,你不能使用EnumMap
。 此外,使用<E extends Enum<E> & A>
,有界通配符的版本<? extends Enum<?> & A>
<? extends Enum<?> & A>
不存在。 鉴于此,您可以使用<E extends Enum<E> & A>
构造对包含静态类型检查的对象包装地图键。
class EnumAWrapper{
final Enum<?> enumObj;
final A aObj;
<E extends Enum<E> & A> EnumAWrapper(E enumA){
enumObj = enumA;
aObj = enumA;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((aObj == null) ? 0 : aObj.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
EnumAWrapper other = (EnumAWrapper) obj;
if (aObj == null) {
if (other.aObj != null)
return false;
} else if (!aObj.equals(other.aObj))
return false;
return true;
}
}
这是一个演示:
Map<EnumAWrapper, String> map = new HashMap<>();
//does compile
map.put(new EnumAWrapper(C.c1), "");
map.put(new EnumAWrapper(D.d1), "");
map.put(new EnumAWrapper(E.e1), "");
A aObj = map.keySet().iterator().next().aObj;
Enum<?> enumObj = map.keySet().iterator().next().enumObj;
//does not compile (given that enum F does not implement A)
map.put(new EnumAWrapper(new A(){}), "");
map.put(new EnumAWrapper(F.f1), "");
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.