我正在查看一些过去的OOP考试试卷,我将非常感谢您理解以下代码。问题是,鉴于第一个代码块并且Sandwich实现了Edible,以下哪些陈述是合法的?
Sandwich sub = new Sandwich();
Rectangle cerealBox = new Rectangle(20,30,20,10);
Edible e = null;
e = sub;
sub = e;
sub = (Sandwich) e;
sub = (Sandwich) cerealBox;
e = cerealBox;
e = (Edible) cerealBox;
e = (Rectangle) cerealBox;
e = (Rectangle) null;
e = (Edible) sub;
cerealBox = (Rectangle) new Object();
我目前的理解是第一个陈述是正确的,因为sub具有构成可食用对象所需的元素,因此它对于第二个语句不起作用。并且使用第三个语句转换确实允许这个工作。但第四个不是因为cerealBox不适用于三明治。然后最后两个因为铸造而起作用。但显然第六个有效吗?
对于我所知道的可怕解释感到抱歉,我们将不胜感激。
答案 0 :(得分:6)
Java中的继承和接口实现据说代表了“is-a”关系。也就是说,如果Boy
继承自Person
,那么Boy
就是Person
。因此,可以将视为 a Person
(因为它是)。这尤其意味着可以将其分配给类型为Person
的实例。
有了这个,我们可以决定
e = sub
编译并运行正常。的 [OK] 强> sub = e
不编译:一个is-a关系不能被逆转。的 [!] 强> sub = (Sandwich) e
强制以上内容通过显式转换进行编译。此外,由于此时的e
包含三明治(来自赋值1),因此此转换也会在运行时成功。的 [OK] 强> sub = (Sandwich) cerealBox
- 由于没有从Rectangle
到Sandwich
的有意义转换,因此无法编译。的 [!] 强> e = cerealBox
- 同样在这里,出于同样的原因。的 [!] 强> e = (Edible) cerealBox
这里,Java编译器投降:它允许强制转换,即使我们(程序员)知道它不能成功,因为cerealBox
中包含的对象没有实现Edible
- 但编译器无法知道这一点:可以想象,其中包含的对象可以从Rectangle
派生(因此可分配给cerealBox
),而也< / em>实施Edible
。
所以编译器默认。但在运行时,您将获得ClassCastException
。
请注意此声明与4的不同之处:编译器知道cerealBox
不能包含Sandwich
。但它可以包含Edible
的内容。为什么?因为Java是单继承(并且Rectangle
不从Sandwich
继承),但允许从多个接口扩展。的 [C] 强>
e = (Rectangle) cerealBox
失败,因为演员实际上完全没有意义(cerealBox
已经是Rectangle
类型),剩下的陈述相当于5. [!] 强> e = (Rectangle) null
失败,即使null
可以分配给Edible
对象。但是演员因为5无效而使其无效。的 [!] 强> e = (Edible) sub
有效,等同于1.然而,强制转换是完全冗余的,因为Java会在继承层次结构中隐式执行向上转换。的 [OK] 强> cerealBox = (Rectangle) new Object()
编译,并在运行时崩溃。原因类似于6:Object
是Rectangle
的基类;因此,一个对象可以包含一个Rectangle
实例,这将使该语句成功(参见3中的一个示例)。
是的,编译器有点愚蠢 - 可以看到正在投射的对象 - new Object()
- 绝不可能是Rectangle
。但编译器不进行此分析,因为在一般情况下这是不可能的。的 [C] 强>
键:[确定] =编译,运行无错误。 [C] =编译,崩溃。 [!] =无法编译。
正如您所看到的,哪些语句是“合法的”并不能完全消除它:其中一些语句会编译,但会在运行时产生异常。他们合法吗?
答案 1 :(得分:1)
第六个不起作用。 Rectangle不实现Edible,因此无法将其转换为它。
编辑:请参阅Vulcan的注释,了解IDE允许的原因。您将收到运行时错误。