java:反射以获取枚举

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4750965/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 07:51:20  来源:igfitidea点击:

java: reflection to obtain an Enum

javareflectionenums

提问by Jason S

This is similar but not quite the same as Java: instantiating an enum using reflection

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

I have a Map<Enum<?>, FooHandler>that I want to use to map Enums (I don't care which type or even if they are the same type, just as long as they are enum constants) to my FooHandlerclass.

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

I would like to populate this map using a text file that I read. I can get it to work, but I have two warnings I would like to get around:

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

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);
}

Warning #1: unchecked cast Warning #2: Enum is a raw type.

警告 #1:未经检查的强制转换警告 #2:枚举是原始类型。

I get #1 and could just put a warning I suppose, but I can't seem to beat warning #2; I've tried Enum<?>and that just gives me an error about generic type capture bound mismatch.

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



Alternative implementations that are worse: Before my <E extends Enum<E>>generic return value, I tried returning Enum and it didn't work; I got these warnings/errors:

更糟糕的替代实现:在我的<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. warnings:

      - 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. errors:

    - 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>>
    
  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>>
    

and this:

还有这个:

static private Enum<?> getEnum(String enumFullName) {
   ...
  Class<Enum<?>> cl = (Class<Enum<?>>)Class.forName(enumClassName);
  // 1
  return Enum.valueOf(cl, enumName);
  // 2
  1. warning: Type safety: Unchecked cast from Class<capture#3-of ?> to Class<Enum<?>>
  2. error: 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>>
  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>>

采纳答案by maaartinus

For #1 there's no solution except SuppressWarnings("unchecked").

对于#1,除了SuppressWarnings("unchecked").

For #2 there's a problem with the declaration:

对于#2,声明有问题:

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

You can return E, but there's no way for the compiler to determine E. There's no argument of type Eor Class<E>or whatever, which would allow it. You can write it, but there'll be an unchecked cast somewhere and when you call it, you may get a ClassCastException. So don't do it.

您可以返回E,但编译器无法确定E。没有类型EClass<E>其他类型的参数,这将允许它。你可以写它,但在某处会有一个未经检查的强制转换,当你调用它时,你可能会得到一个ClassCastException. 所以不要这样做。

Just change it into

把它改成

static private Enum<?> getEnum(String enumFullName)

as this will work and is more fair. You'll get a warning on each call site and that's correct as there is something to warn of.

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

回答by ColinD

The signature

签名

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

isn't doing you any good here.

在这里对你没有任何好处。

The <E extends Enum<E>>allows the caller of the method to assign the result of getEnumto any enumtype they want without any casting:

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

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

However, that doesn't make any sense... if the caller knew what specific type of enumthe method would return, they could do something more sensible like SomeEnum.valueOf("SOMETHING").

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

The only thing that makes sense here is for getEnumto just return Enum<?>, which seems like what you really want to do anyway:

这里唯一有意义的是getEnumreturn 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;
}

The above compiles with no warnings and works properly. The cast to Class<Enum>warning is suppressed because we know that it isn't safe to do that and that Enum.valueOfwill blow up if the class with the given name isn't an enumclass and that's what we want to do.

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