2011-03-10 98 views
17

我试图做到以下几点:如果我在编译时不知道类,我该如何获得Enum的值?

Class<?> cls = unknownClass; 
if(cls.isEnum()){ 
    @SuppressWarnings("unchecked") 
    Class<? extends Enum<?>> enumClass = (Class<? extends Enum<?>>) cls; 
    Object val = Enum.valueOf(enumClass, "NAME1"); 
} 

,但我得到了以下错误:

Bound mismatch: The generic method valueOf(Class<T>, String) of type Enum<E> is 
not applicable for the arguments (Class<capture#5-of ? extends Enum<?>>, String). 
The inferred type capture#5-of ? extends Enum<?> is not a valid substitute for 
the bounded parameter <T extends Enum<T>> 

谁能告诉我什么,我做错了什么?

回答

20

鉴于中投不会真正是检查的事情,我会去与完全不成熟版本:

if (cls.isEnum()){ 
    @SuppressWarnings("unchecked") 
    Object val = Enum.valueOf(cls, "NAME1"); 
} 

,似乎工作。完整的例子:

public class Test 
{ 
    enum Foo 
    { 
     BAR, BAZ 
    } 


    public static void main(String[] args) 
    { 
     @SuppressWarnings("rawtypes") 
     Class cls = Foo.class; 

     if (cls.isEnum()) 
     {   
      @SuppressWarnings("unchecked") 
      Object value = Enum.valueOf(cls, "BAR"); 
      System.out.println(value); 
     } 
    } 
} 
+0

这不工作(或者是它只是我的编译器)?:) – dacwe 2011-03-10 16:17:47

+0

@dacwe:它可以在* my *编译器上工作 - 但是您还没有用什么方式说*它不起作用。我将展示一个简短但完整的示例... – 2011-03-10 16:19:19

+0

啊,对不起,它不能编译。 '类 cls = SomeEnum.class; Object val = Enum.valueOf(cls,“NAME1”);'和我得到一个类似于'Bound bound mismatch'的提问者。 – dacwe 2011-03-10 16:21:36

6

的问题是,你有两个?,他们可以是不同的,他们必须是相同的。

要么你必须使用非通用的声明泛型类型像

public static <T extends Enum<T>> T val(Class<T> cls) { 
    if(cls.isEnum()) { // is redundant when the compiler checks this. 
     @SuppressWarnings("unchecked") 
     Class<T> enumClass = (Class<T>) cls; 
     T val = Enum.valueOf(enumClass, "NAME1"); 
     return val; 
    } 
    return null; 
} 

然而,调用此方法是有点噩梦也是如此。 ;)

+0

'T '被定义为扩展了'Enum '的类,这是由于Enum的繁琐/递归声明'public class Enum >' – 2011-03-10 15:57:43

+0

@Peter:是的,但它只是将被完全擦除,因为调用者无法与T相互作用 – 2011-03-10 15:59:26

+0

正如你所写的那样,如何*做*我称之为方法?:) – dacwe 2011-03-10 15:59:45

3

​​会给所有的枚举,然后你就可以找到一个你感兴趣的

修改乔恩的代码:

public class Test { 
    private enum Foo { 
     BAR, BAZ 
    } 

    public static void main(String[] args) { 
     Class<?> cls = Foo.class; 

     if (cls.isEnum()) { 
      for (Object constant : cls.getEnumConstants()) { 
       Enum<?> enumConstant = (Enum<?>)constant; 
       if (enumConstant.name().equals("BAR")) { 
        System.out.println(constant); 
        break; 
       } 
      } 
     } 
    } 
} 

在Java SE 8,你可能是。能够用lambda和抽象控制流来做一些聪明的事情。

注:

  • 反思是几乎总是一个非常糟糕的主意。
  • 不需要未经检查的警告或抑制这些有效的警告。
  • 不需要rawtypes(其拼写和语义)警告或抑制这些有效的警告。
  • 不需要无谓的咆哮。
  • 无需downvote这个答案。
+0

我喜欢这一点,如果我不知道编译时的枚举类型,这个解决方案不会引发编译器警告。我可以只有一个foo类型的实例并调用fooInstance.getClass()并将其用于cls。 – Cameron 2013-03-07 23:09:44

1

使用原始类型是很好的。虽然Java不愿意添加原始类型,但它已被证明是必要的且不可或缺的,而不是向后兼容性问题。

没有原始类型,为了以理论上完美的方式解决您的问题,Java必须更加复杂。它可能需要一个类型变量变量。那时,代码不再是讨好人类,而是取悦机器。 (我们可能已经在这一点上,考虑到所有的泛型代码,无法理解)

-1
class EnumValues<P extends Enum<P>> 
    { 
     public static <P extends Enum<P>> P [] getValues(Class<P> keyType) 
     { 
      return keyType.getEnumConstants(); 
     } 
    } 

用法:

Class cls = Thread.State.class; 
    for(Enum en : EnumValues.getValues(cls)) 
     System.out.println(en.name()); 
+0

使用原始类型调用泛型方法在淘气方面有点不足。有效地,那里有一个不受控制的演员。最近的编译器会给你警告(注意他们!)。 (不是我downvote,顺便说一句。) – 2012-02-27 02:49:52

相关问题