这个问题与to a previous question有关。可以通过添加强制转换来解决原始问题以执行未经检查的转换。所以现在我有以下代码:
import java.util.EnumSet;
class A {
static enum E1 {
X
}
private static <T extends Enum<T>> EnumSet<T> barEnum(Class<T> x) {
return null;
}
private static void foo1(EnumSet<E1> s, E1 e) {
EnumSet<E1> x2 = barEnum((Class<E1>)e.getClass());
}
private static void foo2(EnumSet<E1> s) {
EnumSet<E1> x = barEnum((Class<E1>)s.iterator().next().getClass());
}
}
我最初的意图是编写一个通用方法。所以我将方法foo2()
概括为:
private static <E extends Enum<E>> void foo3(EnumSet<E> s) {
EnumSet<E> x = barEnum(s.iterator().next().getClass());
}
这显然包含未经检查的转换,并使用适当的警告进行编译。但我不会将getClass()
的结果明确地投射到Class<E>
。由于foo1()
是泛型方法foo3()
的一个实例,我希望我也需要在这里添加转换。比较foo1()
与foo4()
...
private static void foo4(EnumSet<E1> s) {
EnumSet<E1> x = barEnum(s.iterator().next().getClass());
}
......这两者实际上是相似的(主要区别在于E1 e
中的foo1()
参数)。但是foo1()
编译,但foo4()
无法编译。我觉得这是不一致的。是否有允许对泛型方法进行隐式转换的规则?
答案 0 :(得分:2)
发生了两件事。首先,如果您查看getClass
的javadoc,它会说:
实际结果类型为
Class<? extends |X|>
,其中|X|
是要调用getClass
的表达式的静态类型的擦除。
这意味着在您的通用方法中,使用barEnum
而不是Class<? extends Enum>
调用Class<? extends Enum<E>>
。由于Enum
是原始类型,因此会创建一个未经检查的调用,这反过来意味着将删除返回类型(另请参阅:Why is generic of a return type erased when there is an unchecked conversion of a method parameter in Java 8?)。
因此,在这种情况下,barEnum
实际上会返回EnumSet
,这是一种可以未经检查转换为EnumSet<E>
的原始类型。
对于非泛型方法,您必须将参数显式转换为Class<E1>
,因此没有未经检查的方法参数转换,因此没有未经检查的调用。但是,这也意味着不会删除返回类型,并且编译器找不到对该调用有效的T
。
答案 1 :(得分:0)
我的建议是阅读优秀的Java Generics FAQ: http://www.angelikalanger.com/GenericsFAQ/JavaGenericsFAQ.html
由于静态方法不会继承泛型类的类型参数,因此无法编译。然后,您尝试获取参数化类型的运行时类信息,这些信息不会起作用,因为Java使用擦除来实现其泛型。
一旦你超越了简单的集合等等,Java中的泛型并不容易。这就是常见问题解答是不可或缺的资源的原因。
答案 2 :(得分:0)
当我为获得的类提取变量并让我的IDE修复&#39;一切都可以,我明白了:
private static void foo4(Iterable<E1> s) {
Class<? extends E1> aClass = s.iterator().next().getClass();
EnumSet<E1> x = barEnum(aClass);
}
如你所见,aClass
是未参数化的(Enum
上有一条警告说它是“原始的”#)。此外,它声明它可以是Enum的任何子类,而barEnum
只接受特定的枚举,并且因为特定的枚举是final
类(它们不能有子类),所以存在冲突。< / p>
然后我将batEnum
更改为
private static <T extends Enum<T>> EnumSet<T> barEnum(Class<? extends T> x) {
错误消失了,因为现在它接受Enum
的子类。