2011-03-10 100 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

相關問題