Java 为什么这是一个未经检查的演员阵容?如何修复它?

Java 为什么这是一个未经检查的演员阵容?如何修复它?,java,generics,iterator,Java,Generics,Iterator,我有以下代码: 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.get

我有以下代码:

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;
}
public final T getComponent(类类型){
迭代器it=components.Iterator();
while(it.hasNext()){
Component next=it.next();
if(键入.isAssignableFrom(next.getClass()))
return(T)next;//为什么这是从组件到T的未检查强制转换?
}
返回null;
}
出于某种原因,
return(T)next是从组件到T的未选中强制转换

我不确定这是为什么,因为T必须扩展组件,它应该能够安全地将其转换为组件的任何子类,对吗


如果我手动执行
下一步返回(TestComponent)并将返回类型更改为TestComponent它可以正常工作,那么为什么它不能与t一起工作?

因为t是组件的子类,每个t都是组件,但不是每个组件都是t

如果子类继承自超类,则无法成功执行将超类强制转换为子类的操作


因此,不能将新组件强制转换为T实例。

其他人已经描述了该问题,以下是解决方案(使用cleaner test):


这是未经检查的强制转换,因为编译器无法确定
next
T
。它只知道它是一个
组件

至于您的问题,为什么强制转换到
T
会生成警告,而不是强制转换到
TestComponent
,这要微妙得多。转换为
TestComponent
本质上比转换为
T
更不可靠。如果
test
不是
TestComponent
,则转换为
TestComponent
将在运行时导致
ClassCastException
。但强制转换为
t
的情况并非如此,因为由于类型擦除,类型
t
在运行时是未知的。如果您将一个非
T
组件
强制转换为
T
,然后将结果添加到
列表
,您将拥有一个
列表
,其中并非所有项目都是
T
s。这将打破仿制药应该提供的保证。不会有
ClassCastException
阻止这种情况发生


就你而言,你不必担心。通过传递
对象并进行检查,您已经检查了对
T
的强制转换是否安全。你有两个选择。您可以抑制警告并添加注释,解释为什么这样做是安全的。然而,更好的选择是编写
返回类型.cast(下一步)取而代之。这不会生成警告,因为如果
object
不是
t
,则
type.cast(object)
将抛出
ClassCastException

然而,在我的例子中,我看到行
if(type.isAssignableFrom(next.getClass()){
确保
next
T
类型,对吗?是
isAssignableFrom()
检查类型是否相同,或者是
next.getClass()的超类/超接口
。因此,如果
T
组件
的类型相同,这将返回true,但您仍然无法将
组件
强制转换为
T
实例,因为并非每个
组件
都将是
T
实例,因此编译器不允许使用它。我明白了,所以从技术上讲,它确实检查了
实例xt
T
的一个实例,但编译器不知道这一点,因此发出了警告。是的,很抱歉,我在上面的评论中被搞混了。它检查
next
是否是
T
的一个实例/超类/超接口,而不是像我在上面的评论中所说的那样。也就是说,它检查参数是否传入
IsAssignableFrom()
是调用
isAssignableFrom()
所引用的对象的实例/超类/超接口。使用@SuppressWarnings是不正确的,原因与执行“捕获(异常)”是不正确的。“我确定我没有犯错误”这不是一个很好的理由;人们确实会犯错误,方法会在以后被修改。@VGR这是胡说八道。如果你能证明某些东西是安全的,那么完全可以取消警告并添加注释来解释为什么可以。这是Josh Bloch在有效Java中的建议。@pbabcdefp是正确的。取消警告也可以当您完全确定代码不会导致问题时,例如运行时异常。请确保对警告的抑制覆盖了尽可能小的范围。@DermotBlair实际上我认为我只正确了一半。如果您真的没有其他选择,则可以抑制警告,只要您能证明它是安全的。但在这种情况下,y您确实可以选择编写
返回类型.cast(下一步);
作为已接受的答案。是的,我同意,当您有选择时,不应使用它。在本例中,绝对不应使用它。仅当您需要消除编译器警告时(例如,公司政策)才应使用它你肯定知道代码是安全的,但是@VGR说“使用@SuppressWarnings永远都不正确”,我认为这有点不正确。
if(type.isInstance(next) {
  return type.cast(next);
}