具有通用类型枚举的通用枚举

时间:2017-01-18 21:36:15

标签: java

我有以下界面和类定义。

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帖子: How to implement enum with generics?

4 个答案:

答案 0 :(得分:1)

您无法使用EnumMap执行此操作。

EnumMap需要一个单一类型的键 - 构造函数可以通过将泛型类型绑定到具体类型来强制执行此操作。

在底层,它构建了一个可用键值缓存,用于强制运行时类型安全。

如果您想允许来自层次结构的密钥,则需要使用其他类型的地图。

答案 1 :(得分:0)

试试这个:

private Map<Enum<? extends A>, String> myMap;

这会将类型绑定到任何实现A的枚举。

这相当于<? extends Enum<?> & A>,但更容易输入。

答案 2 :(得分:0)

我会说teppic所说的 - 你不能A一般地使用HashMap的所有子类。它必须用特定的具体类构建。请参阅EnumMap的JavaDoc

https://docs.oracle.com/javase/7/docs/api/java/util/EnumMap.html

我看到你似乎有两个选择

使用其他类型的地图实施(例如Map<A, String> myMap1 = new HashMap<>(); myMap1.put(C.c1, C.c1.name()); System.out.println(myMap1);

{c1=c1}

输出结果为:

A

实施EnumMap的又一个子类,以便您可以使用EnumMap

如果出于某些原因,您确实想要使用C,那么 想要将DEA的所有值都实现为一个枚举,你还有 以下解决方案。

在以下代码示例中实现SuperCde的新子类(让我们称之为C)具有DE的所有可能值,和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}

输出结果为:

{{1}}

答案 3 :(得分:0)

正如其他人所指出的,你不能使用EnumMap。此外,在使用<E extends Enum<E> & 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), "");