为什么这是一个未经检查的演员表?以及如何解决?

Why is this an unchecked cast? And how to fix it?

我有以下代码:

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; 并将 return 类型更改为 TestComponent 它工作正常,那么为什么它不能与 T 一起工作?

由于T是Component的子类,所以每个T都是一个Component,但不是每个Component都是T。

如果子类继承自超类,则无法成功将超类转换为子类。

因此无法将新组件转换为 T 实例。

其他人已经描述了问题,这里是解决方案(使用更清洁的测试):

if(type.isInstance(next) {
  return type.cast(next);
}

这是一个未经检查的转换,因为编译器无法确定 nextT。它只知道它是一个 Component.

至于为什么转换为 T 会生成警告,而不是转换为 TestComponent,这个问题要微妙得多。投射到 TestComponent 本质上比投射到 T 更狡猾。如果 test 不是 TestComponent,转换为 TestComponent 将在运行时导致 ClassCastException。但这不是转换为 T 的情况,因为由于类型擦除,类型 T 在运行时是未知的。如果您将不是 TComponent 转换为 T,然后将结果添加到 List<T>,您将得到一个 List<T>,其中不是全部的项目是 Ts。这将破坏泛型应该提供的保证。 ClassCastException 不可能阻止这种情况。

对于你的情况,你不必担心。通过传递 Class<T> 对象并进行检查,您已经检查到 T 的转换是安全的。你有两个选择。您 可以 取消警告并添加注释解释为什么这样做是安全的。但是,更好的替代方法是改写 return type.cast(next);。这不会生成警告,因为如果 object 不是 Ttype.cast(object) 抛出 ClassCastException