我发现,情况1和3的情况下可以在没有错误被编译,但病例2(SubClassB延伸SuperClassA,这是抽象类),我不知道是什么,为什么情况1和3的情况下都没有编译错误。如果是JDK错误,为什么情况2不能通过投检查?
// case 1
List<SuperClassA> a = new ArrayList<>();
SubClassB b = (SubClassB) a;
// case 2
List<Number> m = new ArrayList<>();
Long n = (Long) m; //Error:(xx,yy) java: incompatible types: java.util.List<java.lang.Number> cannot be converted to java.lang.Long
// case 3
List<Exception> e = new ArrayList<>();
RuntimeException d = (RuntimeException) e;
注意这种情况下,1和3的情况下将在运行时都失败。
在编译时,编译器会抱怨不兼容的类型转换只有在语言规范是这么说的。语言规范允许的情况下1和3,因为他们不会100%的失败。
案例1不会100%的失败,只要编译器而言,因为它认为,a
可以包含任何类型的实例实现List<SuperClassA>
。如果有什么的一个子类,SubclassB
真正实现List<SuperClassA>
?而如果a
实际包含的是子类的实例SubclassB
?随后剧组会成功!
同样的问题也发生在情况2.如果想要什么就有什么的子类RuntimeException
真正实现List<Exception>
?而如果e
实际包含的是子类的实例RuntimeException
?随后剧组会成功!
案例2只显示了一个错误,因为Long
是final
。有不能是一个子类实现List<Number>
,所以它肯定会失败。
这是在指定§5.5.1规范(斜体字是相关的位):
给定一个编译时引用类型S(源极)和一个编译时引用类型T(目标),流延转换选自S如果发生没有编译时错误存在至T由于以下规则。
...
如果S是一个接口类型:
如果T是一个数组类型,则S必须是类型
java.io.Serializable
或Cloneable
(由阵列实现的唯一的接口),或编译时会出现误差。如果T是不是一个类或接口类型
final
(§8.1.1),然后,如果存在的T的超类型X,和S的超类型Y,使得X和Y是可证明不同参数化类型,并且所述X和Y的擦除是相同的,则发生编译时间错误。否则,中投始终是法律在编译时(因为即使T没有实现S,T威力的一个子类)。
如果T是最后一类类型,那么:
- 如果S不是参数化的类型或原始类型,则T必须实现S,或发生编译时间错误。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句