给这个:
Class<? extends Enum> enumClass = ...; // being passed in from a constructor
Enum e = Enum.valueOf(enumClass, aString); // produces a warning that looks like
[未选中]未经检查的方法调用: java.lang.Enum中的valueOf(java.lang.Class,java.lang.String)是 应用于(java.lang.Class,java.lang.String)
我不想使用泛型,因为这是一个重大变化。我不想压抑。我不明白为什么会发生这种警告。我想这是因为无法扩展Enum类型。我明白了。但我不明白为什么通配符类会抛出这个奇怪的错误。有没有办法在不使用@SupressWarning
或使用泛型的情况下解决这个问题?
修改:要澄清,使用泛型的以下代码会使警告消失。
class Foo<T extends Enum<T>>{
Class<T> enumClass;
Enum e = Enum.valueOf(enumClass, aString);
}
使用泛型是<T>
的用法。我不能这样做,因为这将是一个巨大的层叠变化。
答案 0 :(得分:4)
Enum
和Class
都是通用的。所以如果你不想要任何警告:
class Foo<T extends Enum<T>>{
Class<T> enumClass;
T e = Enum.valueOf(enumClass, str);
}
或者您可以使用通用方法:
public <T extends Enum<T>> T getEnumValue(Class<T> clazz, String name) {
T e = Enum.valueOf(clazz, name);
return e;
}
但是如果你不使用泛型,那么你使用的是原始类型,因此编译器会发出警告 - 除了抑制它们之外别无选择。
答案 1 :(得分:2)
这似乎是编译器错误 - 它应该是错误,而不是警告。
在编译方法调用表达式Enum.valueOf(enumClass...)
时,首先,将捕获转换应用于参数类型。
<W extends Enum> // a new type parameter
Class<W> enumClass; // the type of the argument after capture conversion
然后,对Enum.<T>valueOf(enumClass...)
进行了类型推断,结果为T=W
。
然后,检查替换后T
的界限,即W
是否为Enum<W>
的子类型。
(对于15.12.2.2和15.12.2.3,这个过程是相同的; 15.12.2.7肯定会产生T = W)
此处,检查应该失败。所有编译器都知道W
是Enum
的子类型,它不能推断出W
是Enum<W>
的子类型。 (嗯,我们知道这是真的,禁止W=Enum
;但是这种知识在子类型规则中不存在,因此编译器不会使用它 - 我们可以通过使用MyEnum
层次结构来演示此示例来验证这一点,编译器的行为相同。)
那么为什么编译器仅通过警告传递绑定检查?还有另一条规则允许使用未经检查的警告从Raw
到Raw<X>
进行分配。为什么允许这是另一个问题(它不应该是),但编译器确实感觉Raw
可赋予Raw<X>
。显然这个规则被错误地混合到上面的子类型检查步骤中,编译器认为既然W
是Enum
,它也是某种Enum<W>
,编译器只通过一个警告传递子类型检查,违反规范。
如果这样的方法调用不能编译,那么正确的方法是什么?我看不到任何内容 - 只要参数enumClass
的类型不在Class<X extends Enum<X>>
的递归形式中,任何数量的转换/转换都不能使其成为该形式,因此无法匹配Enum.valueOf
方法的签名。也许javac人故意违反规范只是为了让这种代码编译好!
答案 2 :(得分:0)
如果你想想valueOf里面发生了什么,你会发现你的代码不可能像写的那样工作。 Enum.valueOf需要一个实际枚举类的实例作为参数;然后简单地遍历该类的values()
寻找匹配。
由于type erasure,泛型不适用于您的代码。没有实际类型传递到Enum.valueOf
。