java.lang.Classgenerics和通配符
为什么以下代码无法编译?
interface Iface { } class Impl implements Iface { } class TestCase { static Class<? extends Iface> clazz = Impl.class; }
错误是
java:不兼容的类型:
java.lang.Class
无法转换为java.lang.Class<? extends Iface>
java.lang.Class<? extends Iface>
但我不明白为什么通配符不能捕获。
这里的子类型关系是:
Class extends Iface> ╱ ╲ Class extends Iface>> Class
(我在回答‘无法从List
转换为List
‘时解释了这一点 。) >
所以基本上它不会编译,因为它是一个横向转换。
如果有可能,你可以进行我在那里描述的投射:
(Class extends Iface>>)(Class extends Impl>)Impl.class
如果你不能进行演员表演,那么你可能只需处理一个原始的有界Class extends Iface>
Class extends Iface>
。 它主要是因为警告而烦人,但它开启了出错的可能性:
interface Iface { void accept(T a); } class Impl2 implements Iface { public void accept(String a) { } } class TestCase { static Class extends Iface> clazz = Impl2.class; public static void main(String[] args) throws Exception { // throws ClassCastException clazz.newInstance().accept(new Object()); } }
不太可能发生,但这取决于你在做什么我想。
我倾向于认为这是Java类型系统的问题。
-
可能应该有一个类型参数的特殊规则
? extends T>
? extends T>
包含一个类型参数? extends T
? extends T
使得例如一个Class extends T>
Class extends T>
转换为Class extends T>>
Class extends T>>
。 从定义子类型的现有方式(T
是T>
的超类型)的角度来看,这没有意义,但从类型安全的角度来看它是有意义的。 -
或者例如
List.class
应该是Class
而不是- >
Class
。 -
或者其他一些比我更聪明的聪明人可以想到。
我上面描述的ClassCastException
的有趣之处在于它完全是人为的。 实际上,使用未经检查的强制转换防止它会导致警告。
我想,只是表明Java中的generics尚未完成。
由于类型擦除 ,当你说Impl.class
你得到一个Class
。 也就是说,你可以说
Class clazz = Impl.class;
generics是编译时类型安全function。