简体   繁体   English

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

[英]Generic Enum with generic type Enum

I have the following interface and class definition. 我有以下接口和类定义。

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;
    }
}

Now I have a class where I declare a Map and assign the enum as key and set a value. 现在我有一个类,我声明一个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));
    }
}

Question : As you see myMap is tied to the enum C. I want to create a generic version of myMap, so I can assign any enum value in the class B. 问题 :如您所见,myMap与枚举C绑定。我想创建myMap的通用版本,因此我可以在B类中分配任何枚举值。

I already went thru the stackoverflow post: How to implement enum with generics? 我已经通过stackoverflow帖子: 如何使用泛型实现枚举?

You can't do this with EnumMap . 你不能用EnumMap做到这一点。

EnumMap requires a key of a single type — the constructor is there to enforce this by tying the generic type to a concrete type. EnumMap需要一个单一类型的键 - 构造函数通过将泛型类型绑定到具体类型来强制执行此操作。

Under the hood it builds a cache of possible key values that it uses to enforce run-time type safety. 在引擎盖下,它构建了一个可能的键值缓存,用于强制运行时类型安全。

You'll need to use another type of map if you want to allow keys from your hierarchy. 如果要允许层次结构中的键,则需要使用其他类型的映射。

Try this: 尝试这个:

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

This puts a bound on the type to any Enum that implements A. 这将类型绑定到任何实现A的Enum。

This is equivalent to <? extends Enum<?> & A> 这相当于<? extends Enum<?> & A> <? extends Enum<?> & A> , but easier to type. <? extends Enum<?> & A> ,但更容易输入。

I would second what teppic said -- you cannot use EnumMap generically with all subclasses of A . 我会说teppic所说的 - 你不能将EnumMap一般用于A所有子类。 It must be constructed with a specific concrete class. 它必须用特定的具体类构建。 See the JavaDoc of EnumMap 请参阅EnumMap的JavaDoc

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

I see that you seems to have two options here 我看到你似乎有两种选择

Use other types of Map implementations (eg HashMap ) 使用其他类型的Map实现(例如HashMap

Map<A, String> myMap1 = new HashMap<>();
myMap1.put(C.c1, C.c1.name());
System.out.println(myMap1);

The output would be: 输出将是:

{c1=c1}

Implement yet another subclasses of A so that you can use EnumMap 实现A另一个子类,以便您可以使用EnumMap

If, for some reasons, you really want to use EnumMap , and you do not want to implement all the values of C , D , E into one enum, you still have the following solution. 如果由于某些原因,您确实想要使用EnumMap并且您不希望将CDE所有值都实现为一个枚举,那么您仍然可以使用以下解决方案。

Implement a new subclasses of A (let's call it SuperCde in the following code example) that has all the possible values of C , D , and E , and it has a static method getSuperCde() that serves as a bridge: 实现A的新子类(在下面的代码示例中称之为SuperCde ),它具有CDE所有可能值,并且它有一个静态方法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();
        }
    }
}

And then you can use the following code: 然后您可以使用以下代码:

Map<SuperCde, String> myMap2 = new EnumMap<SuperCde, String>(SuperCde.class);       
myMap2.put(SuperCde.getSuperCde(C.c1), C.c1.name());
System.out.println(myMap2);

The output would be: 输出将是:

{c1=c1}

As pointed out by others you cannot use EnumMap . 正如其他人所指出的,你不能使用EnumMap Also, while using <E extends Enum<E> & A> works, the version for bounded wildcards <? extends Enum<?> & A> 此外,使用<E extends Enum<E> & A> ,有界通配符的版本<? extends Enum<?> & A> <? extends Enum<?> & A> does not exist. <? extends Enum<?> & A>不存在。 Given that, you could wrap your map key with an object that does the static type checking using the <E extends Enum<E> & A> construct. 鉴于此,您可以使用<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;
    }

}

Here is a demo: 这是一个演示:

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM