将 Generic 与 Class<?> 参数一起使用时出错

Error when using Generic with Class<?> parameter

将泛型与枚举一起使用时遇到一些问题:

enum MyEnum1 {
    // ...
    public static MyEnum fromString(String enumStr) { /* ... */ }
}

enum MyEnum2 {
    // ...
    public static MyEnum fromString(String enumStr) { /* ... */ }
}

enum MyEnum3 {
    // ...
    public static MyEnum fromString(String enumStr) { /* ... */ }
}

class MyClass {
    Map<Class<? extends Enum<?>, EnumSet<? extends Enum<?>>> map;

    public <E extends Enum<E>> void addValue2EnumSet(Class<E> enumType, E value);

    // enumType and valueStr is of the same length
    public static Map<Class<? extends Enum<?>, EnumSet<? extends Enum<?>>> getMapOfEnumSet(Class<? extends Enum<?>>[] enumTypes, String[] valueStrs) {
        MyClass c = // ...
        for (int i = 0; i < enumTypes.length; ++i) {
            // for each enumType and valueStr pair
            // add the value (= Enum1/2/3.fromString(valueStr)) to the Map
            Class<? extends Enum<?>> enumType = enumTypes[i];
            String valueStr = valueStrs[i];
            Method fromStringMethod = enumType.getDeclaredMethod("fromString", String.class);

            // error!
            c.addValue2EnumSet(enumType, enumType.cast(fromStringMethod.invoke(null, valueStr))); 
        }
        return c.map;
    }
}

在这一行 c.addValue2EnumSet(enumType, enumType(fromStringMethod.invoke(null, valueStr))); 中,编译错误是第二个参数 Found: 'java.lang.Enum<?>,需要:'?扩展 java.lang.Enum'`

如何在getEnumSetOf()中调用addValue2EnumSet()

此时传递了一个Class<? extends Enum<?> enumType参数,用来判断目标是哪种Enum(Enum1/2/3),然后调用fromString()方法生成相应的 Enum 实例。我不知道从 enumType 获取方法的反射。

难点在于getEnumSetOf的两个参数都是数组,第一个参数的每个元素,例如enumTypes[0],选择第二个参数对应的Enum Type,例如valueStrs[0]。也就是说valueStrs[0]的目标类型是enumTypes[0].

不太确定为什么要使用泛型 - 也许您可以进一步解释。

假设您想通过字符串名称从种子构建枚举集,您可能会发现此技术很有用。其中的关键部分是使用 Enum.getDeclaringClass() 方法。

enum ABEnum {

    A, B;

    public static ABEnum fromString(String enumStr) {
        return ABEnum.valueOf(enumStr);
    }
}

public static Enum fromString(Enum seed, String enumStr) throws Exception {
    Class declaringClass = seed.getDeclaringClass();
    Method fromStringMethod = declaringClass.getDeclaredMethod("fromString", String.class);
    Object result = fromStringMethod.invoke(null, enumStr);
    return (Enum) result;
}

public void test() throws Exception {
    Enum e = fromString(ABEnum.A, "B");
    System.out.println(e);
}

这似乎更接近您的场景 - 它通过反射构建了一个与您的地图非常相似的地图。或许会有帮助。

enum ABEnum {

    A, B, E;

    public static ABEnum fromString(String enumStr) {
        return ABEnum.valueOf(enumStr);
    }
}

enum CDEnum {

    C, D, E;

    public static CDEnum fromString(String enumStr) {
        return CDEnum.valueOf(enumStr);
    }
}

public static Enum fromString(Enum seed, String enumStr) throws Exception {
    Class declaringClass = seed.getDeclaringClass();
    Method fromStringMethod = declaringClass.getDeclaredMethod("fromString", String.class);
    Object result;
    try {
        result = fromStringMethod.invoke(null, enumStr);
    } catch (InvocationTargetException e) {
        result = null;
    }
    return (Enum) result;
}

Map<Class, EnumSet> map = new HashMap<>();

public void test() throws Exception {
    //Enum e = fromString(ABEnum.A, "B");
    Enum[] enums = new Enum[]{ABEnum.A, CDEnum.C};
    String[] names = new String[]{"A", "B", "C", "D", "E"};
    for (Enum e : enums) {
        Class c = e.getClass();
        for (String s : names) {
            EnumSet set = map.get(c);
            if (set == null) {
                map.put(c, set = EnumSet.noneOf(c));
            }
            Enum found = fromString(e, s);
            if (found != null) {
                set.add(found);
            }
        }
    }
    System.out.println(map);
}