Reputation: 1596
I'm looking at some past exam papers for OOP and I would appreciate any help with understanding the following code. The question is, given this first block of code and that Sandwich implements Edible, which of the following statements are legal?
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();
My current understanding is that the first statement is true because a sub has the required elements to make up an edible Object, hence it does not work the other way round for the second statement. And with the third statement casting does allow this to work. But the fourth doesn't because cerealBox doesn't apply to Sandwich. Then the last two do work because of the casting. But apparently the 6th one works?
Sorry about my terrible explanation of what I know, any help would be appreciated.
Upvotes: 2
Views: 419
Reputation: 545588
Inheritance and interface implementation in Java are said to represent an “is-a” relationship. That is, if Boy
inherits from Person
, then Boy
is-a Person
. Consequently, it can be treated as if it were a Person
(because it is). This in particular implies that it can be assigned to an instance of type Person
.
Armed with this, we can decide that
e = sub
compiles and runs fine. [OK]sub = e
, on the other hand, doesn’t compile: an is-a relationship cannot be reversed. [!]sub = (Sandwich) e
forces the above to compile through an explicit cast. Furthermore, since e
at that point does contain a sandwich (from assignment 1), this cast also succeeds at runtime. [OK]sub = (Sandwich) cerealBox
– since there is no meaningful conversion from Rectangle
to Sandwich
, this fails to compile. [!]e = cerealBox
– Same here, for much the same reason. [!]e = (Edible) cerealBox
Here, the Java compiler capitulates: it allows the cast, even though we (the programmers) know that it can’t succeed since the object contained in cerealBox
doesn’t implement Edible
– but the compiler can’t know this: conceivably, the object contained in it could be derived from Rectangle
(and hence assignable to cerealBox
), and also implement Edible
.
So the compiler acquiesces. But at runtime, you’ll get a ClassCastException
.
Note how this statement differs from 4: there, the compiler knew that cerealBox
couldn’t contain a Sandwich
. But it could contain something Edible
. Why? Because Java is single-inheritance (and Rectangle
doesn’t inherit from Sandwich
), but allows extending from multiple interfaces. [C]
e = (Rectangle) cerealBox
fails, since the cast is actually completely meaningless (cerealBox
is already of type Rectangle
) and the remaining statement is equivalent to 5. [!]e = (Rectangle) null
fails, even though null
could be assignable to an Edible
object. But the cast makes this invalid for the same reason as 5 is invalid. [!]e = (Edible) sub
is valid, and equivalent to 1. The cast however is completely redundant, since Java performs casts upwards in the inheritance hierarchy implicitly. [OK]cerealBox = (Rectangle) new Object()
compiles, and crashes at runtime. The reason is similar to 6: Object
is a base class of Rectangle
; hence, an object could contain a Rectangle
instance, which would make this statement succeed (see 3 for an example of that).
True, the compiler is kind of stupid – it could see that the object being cast – new Object()
– in no way could be a Rectangle
. But the compiler doesn’t do this analysis, since it’s impossible in the general case. [C]
Key: [OK] = compiles, runs error-free. [C] = compiles, crashes. [!] = doesn’t compile.
As you can see, the question which statements are “legal” doesn’t quite cut it: some of these statements compile, but yield an exception at runtime. Are they legal?
Upvotes: 6
Reputation: 2698
The 6th wouldn't work. Rectangle does not implement Edible, and as such cannot be casted to it.
Edit: See Vulcan's comment for why it is allowed by the IDE. You will receive a runtime error.
Upvotes: 1