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

时间:2015-03-08 00:44:42

标签: 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.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?

3 个答案:

答案 0 :(得分:5)

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

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

答案 1 :(得分:2)

这是一个未经检查的强制转换,因为编译器无法确定nextT。它只知道它是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不是objectT 抛出{{1}}。

答案 2 :(得分:1)

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

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

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