在下面的代码中,对于显然不兼容的类型的dowcast传递编译:
public class Item {
List<Item> items() { return asList(new Item()); }
Item m = (Item) items();
}
Item
和List<Item>
是完全不同的类型,因此演员阵容永远不会成功。为什么编译器允许这样做?
答案 0 :(得分:52)
List<Item>
很可能是一个项目。例如见:
public class Foo extends Item implements List<Item> {
// implement required methods
}
演员告诉编译器:“我知道你不能确定这是Item类型的对象,但我比你知道的更好,所以请编译”。如果返回的对象不可能是Item的实例(例如,Integer
不能是String
)
在运行时,将检查方法返回的实际对象的类型,如果它实际上不是Item类型的对象,则会得到ClassCastException。
答案 1 :(得分:17)
相关规范条目can be found here。设S为源,T为目标;在这种情况下,源是接口,目标是非最终类型。
如果S是接口类型:
如果T是数组类型,则S必须是
java.io.Serializable
或Cloneable
类型(数组实现的唯一接口),或者 发生编译时错误。如果T是非final的类型(§8.1.1),那么如果存在T的超类型X和S的超类型Y,那么X和Y都是 可证明不同的参数化类型,以及X和X的擦除 Y是相同的,发生编译时错误。
否则,演员在编译时总是合法的(因为即使 T没有实现S,T的子类可能)。
这需要一些读数来直截了当,但让我们从顶部开始。
这也意味着如果我们按照这个片段转换到没有实现接口的最终类,它将无法工作:
如果S不是参数化类型或原始类型,则T必须实现S,否则会发生编译时错误。