java:反射获取枚举

Jas*_*n S 8 java reflection enums

这与Java类似但不完全相同:使用反射实例化枚举

我有一个Map<Enum<?>, FooHandler>我想用来映射Enums(我不关心哪种类型,或者即使它们是同一类型,只要它们是枚举常量)到我的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);
}
Run Code Online (Sandbox Code Playgroud)

警告#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
}
Run Code Online (Sandbox Code Playgroud)
  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<?>
    
    Run Code Online (Sandbox Code Playgroud)
  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>>
    
    Run Code Online (Sandbox Code Playgroud)

还有这个:

static private Enum<?> getEnum(String enumFullName) {
   ...
  Class<Enum<?>> cl = (Class<Enum<?>>)Class.forName(enumClassName);
  // 1
  return Enum.valueOf(cl, enumName);
  // 2
Run Code Online (Sandbox Code Playgroud)
  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>>

maa*_*nus 6

对于#1,没有解决办法,除了SuppressWarnings("unchecked").

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

static private <E extends Enum<E>> E getEnum(String enumFullName)
Run Code Online (Sandbox Code Playgroud)

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

只需将其更改为

static private Enum<?> getEnum(String enumFullName)
Run Code Online (Sandbox Code Playgroud)

因为这会起作用并且更公平.您将在每个呼叫站点上收到警告,这是正确的,因为有一些警告.


Col*_*inD 6

签名

static private <E extends Enum<E>> getEnum(String enumFullName)
Run Code Online (Sandbox Code Playgroud)

这对你没有好处.

<E extends Enum<E>>允许方法的调用分配的结果getEnum对任何enum他们想要的,没有任何铸造类型:

SomeEnum e = getEnum("com.foo.SomeOtherEnum.SOMETHING"); // ClassCastException!
Run Code Online (Sandbox Code Playgroud)

然而,这没有任何意义......如果调用者知道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;
}
Run Code Online (Sandbox Code Playgroud)

以上编译没有警告并正常工作.演员以Class<Enum>警告被抑制,因为我们知道它是不是安全做到这一点,那Enum.valueOf将炸毁,如果给定名字的类不是一个enum类,这就是我们想要做的.