John
John

Reputation: 1596

OOP, Interfaces, Objects and Casting

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

Answers (2)

Konrad Rudolph
Konrad Rudolph

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

  1. e = sub compiles and runs fine. [OK]
  2. sub = e, on the other hand, doesn’t compile: an is-a relationship cannot be reversed. [!]
  3. 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]
  4. sub = (Sandwich) cerealBox – since there is no meaningful conversion from Rectangle to Sandwich, this fails to compile. [!]
  5. e = cerealBox – Same here, for much the same reason. [!]
  6. 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]

  7. 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. [!]
  8. 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. [!]
  9. 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]
  10. 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

David B
David B

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

Related Questions