Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cast to unimplemented interface compiles

I am not sure I understand code on line 1 below?

interface Talkable{ }
class Device{}
class Phone extends Device implements Talkable{}


Talkable d = (Talkable) new Device(); //line 1
Talkable p = new Phone(); //line 2

I understand line2 since Phone implements Talkable, but Device and Talkable are unrelated, How can line1 be legal?

like image 441
user1529412 Avatar asked Dec 25 '14 17:12

user1529412


3 Answers

The reason the compiler accepts this is explained in the JLS section 5.5.1 (relevant part in bold):

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 S is a class type:

  • If T is a class type, then either |S| <: |T|, or |T| <: |S|. Otherwise, a compile-time error occurs.

Furthermore, 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 (§4.5), and that the erasures of X and Y are the same, a compile-time error occurs.

  • 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).

In your case, a java.lang.ClassCastException will be thrown at runtime since Device cannot be converted to Talkable. But until the program executes, the compiler allows the cast because there may be a subclass of Device that implements Talkable.

like image 170
M A Avatar answered Nov 03 '22 04:11

M A


Actually, in Java it is perfectly valid to cast one related type to another (even if the casting makes little sense). You will get an error during runtime if the types are not compatible.

For example :

    public static void main(String[] args) {
        String s = (String) new Object();
        System.out.println(s.intern());

    }

Compiles fine but gives Exception in thread "main" java.lang.ClassCastException: java.lang.Object cannot be cast to java.lang.String at Sample.main(Sample.java:5) during runtime

like image 9
TheLostMind Avatar answered Nov 03 '22 04:11

TheLostMind


Line 1 will throw a runtime exception. The compiler does not check at compile time if the cast can succesfully be done. This is why it is sometimes advisable to check this first with the instanceof operator.

In general, you can always cast a variable x of type A to any interface C, because there may exist a class B extends A implements C, or a class B implements A, C

The same is not true for casting a variable x of class A to any class D, because there cannot exist a subclass E extends A, D, because a class may not extend multiple classes.

like image 6
wvdz Avatar answered Nov 03 '22 02:11

wvdz