我正在查看一些过去的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();
Run Code Online (Sandbox Code Playgroud)
我目前的理解是第一个陈述是正确的,因为sub具有组成可食用对象所需的元素,因此它不适用于第二个语句.并且使用第三个语句转换确实允许这个工作.但第四个不是因为cerealBox不适用于三明治.然后最后两个因为铸造而起作用.但显然第六个有效吗?
对于我对我所知道的可怕解释感到抱歉,任何帮助都将不胜感激.
据说Java中的继承和接口实现代表了"is-a"关系.也就是说,如果Boy从继承Person,然后Boy是-A Person.因此,可以治疗,好像它是一个Person(因为它是).这尤其意味着可以将其分配给类型的实例Person.
有了这个,我们可以决定
e = sub编译并运行良好.[好]sub = e另一方面,不编译:一个关系是无法逆转的.[!]sub = (Sandwich) e 强制上述内容通过显式强制转换进行编译.此外,由于e此时确实包含三明治(来自作业1),此演员表也会在运行时成功.[好]sub = (Sandwich) cerealBox -既然没有意义的转换,从Rectangle到Sandwich,这无法编译.[!]e = cerealBox - 同样在这里,出于同样的原因.[!]e = (Edible) cerealBox在这里,Java编译器投降:它允许转换,即使我们(程序员)知道它不能成功,因为包含的对象cerealBox没有实现Edible- 但编译器不能知道这个:可以想象,包含的对象在它中可以从Rectangle(并因此可分配cerealBox)派生,并且也可以实现Edible.
所以编译器默许.但是在运行时,你会得到一个ClassCastException.
注意这个语句与4的不同之处在于:编译器知道它cerealBox不能包含a Sandwich.但它可能包含一些东西Edible.为什么?因为Java是单继承(并且Rectangle不从中继承Sandwich),但允许从多个接口扩展.[C]
e = (Rectangle) cerealBox失败,因为演员实际上完全没有意义(cerealBox已经是类型Rectangle),剩下的陈述相当于5. [!]e = (Rectangle) null失败,即使null 可以分配给Edible对象.但是演员因为5无效而使其无效.[!]e = (Edible) sub是有效的,等效于1.然而,转换是完全冗余的,因为Java隐式地在继承层次结构中执行向上转换.[好]cerealBox = (Rectangle) new Object()在运行时编译和崩溃.原因类似于6:Object是基类Rectangle; 因此,一个对象可以包含一个Rectangle实例,这将使该语句成功(参见3的例子).
没错,编译器有点愚蠢 - 它可以看到正在投射的对象 new Object()- 绝不可能是一个Rectangle.但编译器不进行此分析,因为在一般情况下这是不可能的.[C]
键:[确定] =编译,运行无错误.[C] =编译,崩溃.[!] =不编译.
正如您所看到的,哪些语句是"合法的"并不能完全消除它:其中一些语句会编译,但会在运行时产生异常.他们合法吗?