假设有2个班级。 Child
扩展Parent
。
public class Parent {}
和
public class Child extends Parent {}
我知道以下代码不正确:
Child obj = new Parent(); // causes java.lang.Error
或
Child obj = (Child) new Parent(); // causes java.lang.ClassCastException
但是我不明白为什么我在第一种情况下得到编译错误而在第二种情况下得到运行时异常。毕竟,父母永远不能转换或投射到孩子身上。 为什么在编译时没有检查其中第二种情况?
我会非常感谢一个明确而合理的想法!
答案 0 :(得分:6)
Child obj = new Parent();
在这种情况下,如果Parent
对象可以设置为Child
引用,编译器会尝试检查(隐式强制转换),当此转换失败时,会出现编译时错误。
Child obj = (Child) new Parent();
在这种情况下,编译器会发现您正在将Parent
对象显式地转换为Child
,因此编译器将其留给运行时来决定转换是否有效,从某种意义上说,开发人员负责铸造因此,如果此转换失败,则会出现运行时错误。
答案 1 :(得分:2)
Child obj = new Parent(); //导致java.lang.Error
不,不。它会导致编译错误。根本不是一回事。不要通过将不同的东西等同来混淆自己。
编译器尽可能多地检查,并将其余部分留给运行时。在这种情况下,对Child的分配显然是不正确的,可以在编译时检测到。在编译时无法检测到另一种情况。
答案 2 :(得分:1)
在第二种情况下,您使用显式转换。这意味着基本上你告诉编译器你知道将要发生什么。这是告诉编译器类型是什么的一种方式,所以他相信你。
然而,运行时必须完成这项工作......他不能,所以他是理所当然的抱怨。(他/她?..)
答案 3 :(得分:1)
原因是编译器需要额外的工作来检测这种情况,并且它无法在所有情况下都正确。为了使编译错误有时而且不是所有时间都不值得额外的工作。
虽然Parent的实例永远不能是Child,但是对Parent的引用实际上可能指向Child。通常,如果将类型为Parent的表达式转换为Child,则可能成功。要确定编译器不能知道有关Parent类型表达式的额外信息。在这种情况下,它是一个构造函数调用。这是最简单的情况,而且几乎是明显的唯一情况,即Parent类型的表达式不能引用Child类型的实例。为了这么小的好处,为编译器添加额外的复杂性并不值得。