2010-10-25 123 views
26

我想解决与动态枚举查找有关的编译错误(“Bound mismatch:...”)。Enum.valueOf(类<T>枚举类型,字符串名称)问题

基本上我想要实现这样的事情:

String enumName = whatever.getEnumName(); 
Class<? extends Enum<?>> enumClass = whatever.getEnumClass(); 
Enum<?> enumValue = Enum.valueOf(enumClass, enumName); 

无论我做什么,我总是与编译错误告终。老实说,仿制药和枚举是相当mindboggling我...

我在做什么错在这里?

回答

22

我认为它不会像这样工作,除非您有权访问类型变量(通过类型或方法签名)。问题是Enum.valueOf方法签名:

public static <T extends Enum<T>> T valueOf(
    Class<T> enumType, 
    String name 
); 

有没有办法让一件T没有一个类型变量。但是你可以做这样的,如果你愿意抑制一些编译器警告:

public enum King{ 
    ELVIS 
} 

@SuppressWarnings({ "unchecked", "rawtypes" }) 
public static void main(final String[] args){ 
    final Class<? extends Enum> enumType = King.class; 
    final Enum<?> theOneAndOnly = Enum.valueOf(enumType, "ELVIS"); 
    System.out.println(theOneAndOnly.name()); 
} 

输出:

ELVIS

+0

的问题是关于枚举,泛型和反思。如果忽略泛型,这有什么意义?特别是像“Class <?extends Enum”这样的“稀有类型”。 – 2010-10-25 12:28:04

+2

问题是a)如果没有辅助方法或类型,它就无法工作,b)我们确信任何'类<?扩展枚举>'也将满足'Class >'(因为这就是枚举类的工作方式),即使没有办法检查没有类型变量。 '@ SuppressWarnings'是一个注释,只有在你知道自己在做什么时才应该使用,而且我知道。 – 2010-10-25 12:43:08

19

问题是与Class<? extends Enum<?>>。我们想要E extends Enum<E>,但我们不能得到,因为我们有两个不同的通配符。

因此,我们需要引入一个泛型参数,可以通过调用一个方法介绍:

enum MyEnum { 
    ME; 
} 

public class EnName { 
    public static void main(String[] args) { 
     Enum<?> value = of(MyEnum.class, "ME"); 
     System.err.println(value); 
    } 
    private static <E extends Enum<E>> E of(Class<E> clazz, String name) { 
     E value = Enum.valueOf(clazz, name); 
     return value; 
    } 
} 

但反射粪,很少你想要什么。不要这样做。

+1

感谢您的解释,它对进一步了解正在发生的事情有很大的帮助。因为在我的特定用例中,我没有任何东西可以作为泛型参数提供,所以我会去寻求seanizer的答案。 – Tom 2010-10-25 12:54:39

6

实际上有一种替代方法:你可以使用​​并且自己实现Enum.valueOf,它没有相同类型的问题。不足之处是你找回了一个通用的Enum<?> - 但是如果你知道你进入的是什么类型,那么无论如何你都可以使用Enum.valueOf

private static Enum<?> findEnumValue(Class<? extends Enum<?>> enumType, String value) { 
    return Arrays.stream(enumType.getEnumConstants()) 
       .filter(e -> e.name().equals(value)) 
       .findFirst() 
       .orElse(null); 
} 

(请注意,我的版本返回null如果没有这种持续而不是抛出IllegalArgumentException,但这是改变一件微不足道的小事。