java:反射获取枚举

时间:2011-01-20 18:25:51

标签: java reflection enums

这与Java: instantiating an enum using reflection

类似但不完全相同

我有一个Map<Enum<?>, FooHandler>我想用来映射Enum(我不关心哪种类型,或者即使它们是相同的类型,只要它们是枚举常量)到我的FooHandler班。

我想使用我阅读的文本文件填充此地图。我可以让它工作,但我有两个警告,我想绕过:

static private <E extends Enum<E>> E getEnum(String enumFullName) {
  // see https://stackoverflow.com/questions/4545937/
  String[] x = enumFullName.split("\\.(?=[^\\.]+$)");
  if (x.length == 2)
  {
    String enumClassName = x[0];
    String enumName = x[1];
    try {
      Class<E> cl = (Class<E>)Class.forName(enumClassName);
      // #1                          

      return Enum.valueOf(cl, enumName);
    }
    catch (ClassNotFoundException e) {
      e.printStackTrace();
    }
  }
  return null;
}

public void someMethod(String enumName, String fooHandlerName)
{
   FooHandler fooHandler = getFooHandler(fooHandlerName);
   Enum e = getEnum(enumName);
   // #2

   map.put(e, fooHandler);
}

警告#1:未经检查的演员 警告#2:枚举是一种原始类型。

我得到了#1并且可能只是发出警告我想,但我似乎无法击败警告#2;我试过Enum<?>,这只是给我一个关于泛型类型捕获绑定不匹配的错误。


更糟糕的替代实施: 在我的<E extends Enum<E>>泛型返回值之前,我尝试返回Enum并且它不起作用;我收到了这些警告/错误:

static private Enum<?> getEnum(String enumFullName) {
   ...

Class<?> cl = (Class<?>)Class.forName(enumClassName);
    // 1
return Enum.valueOf(cl, enumName);
    // 2
}
  1. 警告:

      - Type safety: Unchecked cast from Class<capture#3-of ?> to Class<Enum>
      - Enum is a raw type. References to generic type Enum<E> should be parameterized
      - Enum is a raw type. References to generic type Enum<E> should be parameterized
      - Unnecessary cast from Class<capture#3-of ?> to Class<?>
    
  2. 错误:

    - Type mismatch: cannot convert from capture#5-of ? to Enum<?>
    - Type safety: Unchecked invocation valueOf(Class<Enum>, String) of the generic method 
     valueOf(Class<T>, String) of type Enum
    - Bound mismatch: The generic method valueOf(Class<T>, String) of type Enum<E> is not 
     applicable for the arguments (Class<capture#5-of ?>, String). The inferred type capture#5-of ? is not 
     a valid substitute for the bounded parameter <T extends Enum<T>>
    
  3. 和此:

    static private Enum<?> getEnum(String enumFullName) {
       ...
      Class<Enum<?>> cl = (Class<Enum<?>>)Class.forName(enumClassName);
      // 1
      return Enum.valueOf(cl, enumName);
      // 2
    
    1. 警告:Type safety: Unchecked cast from Class<capture#3-of ?> to Class<Enum<?>>
    2. 错误:Bound mismatch: The generic method valueOf(Class<T>, String) of type Enum<E> is not applicable for the arguments (Class<Enum<?>>, String). The inferred type Enum<?> is not a valid substitute for the bounded parameter <T extends Enum<T>>

2 个答案:

答案 0 :(得分:6)

对于#1,除了SuppressWarnings("unchecked")之外没有解决方案。

对于#2,声明存在问题:

static private <E extends Enum<E>> E getEnum(String enumFullName)

您可以返回E,但编译器无法确定E。没有类型EClass<E>或类似的论据,这将允许它。你可以写它,但在某个地方会有一个未经检查的演员,当你调用它时,你可能会得到一个ClassCastException。所以不要这样做。

只需将其更改为

即可
static private Enum<?> getEnum(String enumFullName)

因为这会起作用并且更公平。你会收到每个呼叫网站的警告,这是正确的,因为有警告的东西。

答案 1 :(得分:5)

签名

static private <E extends Enum<E>> getEnum(String enumFullName)

在这里没有任何好处。

<E extends Enum<E>>允许方法的调用者将getEnum的结果分配给他们想要的任何enum类型而不进行任何转换:

SomeEnum e = getEnum("com.foo.SomeOtherEnum.SOMETHING"); // ClassCastException!

然而,这没有任何意义......如果调用者知道该方法将返回哪种特定类型的enum,他们可以做一些比SomeEnum.valueOf("SOMETHING")更明智的事情。

唯一有意义的是getEnum只返回Enum<?>,这似乎是你真正想做的事情:

static private Enum<?> getEnum(String enumFullName) {
  String[] x = enumFullName.split("\\.(?=[^\\.]+$)");
  if(x.length == 2) {
    String enumClassName = x[0];
    String enumName = x[1];
    try {
      @SuppressWarnings("unchecked")
      Class<Enum> cl = (Class<Enum>) Class.forName(enumClassName);
      return Enum.valueOf(cl, enumName);
    }
    catch(ClassNotFoundException e) {
      e.printStackTrace();
    }
  }
  return null;
}

以上编译没有任何警告并正常工作。转换为Class<Enum>警告被抑制,因为我们知道这样做是不安全的,如果具有给定名称的类不是Enum.valueOf类,enum将会爆炸这就是我们想要做的事情。