Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Casting an object to an interface which is not implemented

I found following question in my study book and a bit confused:

Given the following code, which option, if used to replace /* INSERT CODE HERE */, will enable a reference variable of type Roamable to refer to an object of the Phone class? (Select 1 option.)

interface Roamable{}
class Phone {}
class Tablet extends Phone implements Roamable {
    //INSERT CODE HERE
}

Options are:

  1. Roamable var = new Phone();
  2. Roamable var = (Roamable)Phone();
  3. Roamable var = (Roamable)new Phone();
  4. Because interface Roamable and class Phone are unrelated, a reference variable of type Roamable can’t refer to an object of class Phone.

I thought the correct option is 4, however it says it is 3.

But, Phone doesn't implement Roamable interface, so you can't cast, can you?

like image 240
Erdinc Avatar asked Feb 16 '14 14:02

Erdinc


2 Answers

The correct answer is 3: The compiler sees only that a Phone is being cast to a Roamable and that Phone is not final, so it thinks that the object being cast, although referred to as Phone may be a subclass of Phone that does implement Roamable, so no compile-time error or warning is issued.

According to JLS chapter 5

5.5.1. Reference Type Casting

Given a compile-time reference type S (source) and a compile-time reference type T (target), a casting conversion exists from S to T if no compile-time errors occur due to the following rules. If T is an interface type:

If S is not a final class (§8.1.1), then, if there exists a supertype X of T, and a supertype Y of S, such that both X and Y are provably distinct parameterized types, and that the erasures of X and Y are the same, a compile-time error occurs.

Otherwise, the cast is always legal at compile time (because even if S does not implement T, a subclass of S might).

If S is a final class (§8.1.1), then S must implement T, or a compile-time error occurs.


The following code compiles:

interface Roamable{}
class Phone {}
class Tablet extends Phone implements Roamable {
    Roamable var = (Roamable)new Phone(); // Compiles
}
like image 160
Bohemian Avatar answered Oct 02 '22 08:10

Bohemian


Answer would be 4

as

1 is incorrect(explanation --> 4)
2 is incorrect syntax
3 is incorrect typecast.

Note that answer 3 is valid as long as it is just about compilation. When you say you have a instance of Phone class you can type cast into Tablet (Similar to you can cast Object to String). And since Tablet implements Roamable you can very well use a Roamable reference to refer it. Problem will occur at runtime as the Object is really of type Phone.

This is just one of the linkage patter(in current context) which allows successful compilation. But as Bohemian has mentioned in his answer in general

If we are typecasting a compile time reference S(non final) to compile time reference T then compilation will be successful as even if S does not implement T, a subclass of S might. If S is a final class , then S must implement T, or a compile-time error occurs.

Actually there is no need of Tablet class extending Phone class at all. As long as Phone class is not final compilation will be successful

interface Roamable{}
class Phone {}
class Tablet implements Roamable {
    Roamable var = (Roamable)new Phone(); // Compiles
}
like image 28
Aniket Thakur Avatar answered Oct 02 '22 10:10

Aniket Thakur