java.lang.Class 泛型和通配符
java.lang.Class generics and wildcards
为什么下面的代码编译不通过?
interface Iface<T> { }
class Impl<T> implements Iface<T> { }
class TestCase {
static Class<? extends Iface<?>> clazz = Impl.class;
}
错误是
java: incompatible types: java.lang.Class<Impl>
cannot be converted to java.lang.Class<? extends Iface<?>>
但我不明白为什么通配符没有捕获。
因为 type-erasure,当您说 Impl.class
时,您会得到 Class<Impl>
。也就是说,你可以说
Class<Impl> clazz = Impl.class;
泛型是一种编译时类型安全功能。
这里的子类型关系是:
Class<? extends Iface>
╱ ╲
Class<? extends Iface<?>> Class<Impl>
(我在对 'Cannot convert from List<List>
to List<List<?>>
' 的回答中对此进行了解释。)
所以基本上它不会编译,因为它是横向转换。
如果可能的话,你可以做我在那边描述的演员表:
(Class<? extends Iface<?>>)(Class<? extends Impl>)Impl.class
如果您不能进行转换,那么您可能只需要处理原始有界 Class<? extends Iface>
。这主要是因为警告而令人讨厌,但它打开了错误的可能性:
interface Iface<T> {
void accept(T a);
}
class Impl2 implements Iface<String> {
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
,例如Class<? extends T>
转换为 Class<? extends T<?>>
。从现有的子类型定义方式(T
是 T<?>
的超类型)的角度来看,这没有意义,但从类型安全的角度来看,这是有意义的。
或者例如List.class
应该是 Class<List<?>>
而不是 Class<List>
。
或者比我聪明的人能想到的其他聪明的东西。
我上面描述的 ClassCastException
的有趣之处在于它完全是人为的。事实上,用未经检查的强制转换来阻止它会导致警告。
我猜这只是 Java 中泛型尚未完成的标志。
为什么下面的代码编译不通过?
interface Iface<T> { }
class Impl<T> implements Iface<T> { }
class TestCase {
static Class<? extends Iface<?>> clazz = Impl.class;
}
错误是
java: incompatible types:
java.lang.Class<Impl>
cannot be converted tojava.lang.Class<? extends Iface<?>>
但我不明白为什么通配符没有捕获。
因为 type-erasure,当您说 Impl.class
时,您会得到 Class<Impl>
。也就是说,你可以说
Class<Impl> clazz = Impl.class;
泛型是一种编译时类型安全功能。
这里的子类型关系是:
Class<? extends Iface>
╱ ╲
Class<? extends Iface<?>> Class<Impl>
(我在对 'Cannot convert from List<List>
to List<List<?>>
' 的回答中对此进行了解释。)
所以基本上它不会编译,因为它是横向转换。
如果可能的话,你可以做我在那边描述的演员表:
(Class<? extends Iface<?>>)(Class<? extends Impl>)Impl.class
如果您不能进行转换,那么您可能只需要处理原始有界 Class<? extends Iface>
。这主要是因为警告而令人讨厌,但它打开了错误的可能性:
interface Iface<T> {
void accept(T a);
}
class Impl2 implements Iface<String> {
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
,例如Class<? extends T>
转换为Class<? extends T<?>>
。从现有的子类型定义方式(T
是T<?>
的超类型)的角度来看,这没有意义,但从类型安全的角度来看,这是有意义的。或者例如
List.class
应该是Class<List<?>>
而不是Class<List>
。或者比我聪明的人能想到的其他聪明的东西。
我上面描述的 ClassCastException
的有趣之处在于它完全是人为的。事实上,用未经检查的强制转换来阻止它会导致警告。
我猜这只是 Java 中泛型尚未完成的标志。