我有以下代码:
public final <T extends Component> T getComponent(Class<T> type) {
Iterator<Component> it = components.iterator();
while(it.hasNext()) {
Component next = it.next();
if(type.isAssignableFrom(next.getClass()))
return (T)next; // Why is this an unchecked cast from Component to T?
}
return null;
}
由于某些原因,return (T)next;
是从Component到T的未经检查的强制转换。
我不确定为什么会这样,因为T必须扩展Component,它应该能够安全地将它转换为Component的任何子类,对吗?
如果我手动执行return (TestComponent)next;
并将返回类型更改为TestComponent它可以正常工作,那么为什么它不适用于T?
答案 0 :(得分:5)
其他人已经描述了问题,这里是解决方案(使用更清洁的测试):
if(type.isInstance(next) {
return type.cast(next);
}
答案 1 :(得分:2)
这是一个未经检查的强制转换,因为编译器无法确定next
是T
。它只知道它是Component
。
关于为什么投射到T
会产生警告但不投射到TestComponent
的问题,这更加微妙。投射到TestComponent
本身就比投射到T
更少狡猾。如果test
不是TestComponent
,则转换为TestComponent
会在运行时导致ClassCastException
。但是这不是转换为T
的情况,因为在运行时由于类型擦除而未知类型T
。如果您将Component
T
投放到T
,然后将结果添加到List<T>
,那么您将拥有List<T>
并非全部T
这些项目是ClassCastException
s。这将破坏仿制药应该提供的保证。 T
无法阻止此事。
在您的情况下,您不必担心。您已通过传递Class<T>
对象并进行检查,检查了转换为return type.cast(next);
是否安全。你有两个选择。您可以取消警告并添加注释,解释为什么这样做是安全的。但是,更好的选择是编写type.cast(object)
。这不会生成警告,因为如果ClassCastException
不是object
,T
将抛出{{1}}。
答案 2 :(得分:1)
由于T是Component的子类,因此每个T都是一个Component,但不是每个Component都是T。
如果子类继承自超类,则无法将超类强制转换为子类。
因此无法将新Component转换为T实例。