Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why Java allows casting obj with Interface [duplicate]

Tags:

java

casting

public class InterfaceCasting {

    private static class A{}

    public static void main(String[] args) {
        A a = new A();
        Serializable serializable = new Serializable(){};
        a = (A)serializable;
    }

}

Compilation succeed but Runtime exception

Exception in thread "main" java.lang.ClassCastException: InterfaceCasting$1 cannot be cast to InterfaceCasting$A

WHY COMPILATION SUCCEED? Compiler must known that serialiazable is not A?

like image 506
komenan Avatar asked Nov 20 '22 21:11

komenan


2 Answers

As you point out, this will compile:

interface MyInterface {}

class A {}

public class InterfaceCasting {
    public static void main(String[] args) {
        MyInterface myObject = new MyInterface() {};
        A a = (A) myObject;
    }
}

This however, will not compile:

interface MyInterface {}

class A {}

public class InterfaceCasting {
    public static void main(String[] args) {
        A a = (A) new MyInterface() {}; // javac says: "inconvertible types!"
    }
}

So, what's going on here? What's the difference?

Well, since MyInterface is simply an interface, it could very well be implemented by a class that extends A, in which case the cast from MyInterface to A would be legal.


This code for instance, will succeed in 50% of all executions, and illustrates that the compiler would need to solve possibly undecidable problems in order to always "detect" illegal casts at compile time.

interface MyInterface {}

class A {}

class B extends A implements MyInterface {}

public class InterfaceCasting {
    public static void main(String[] args) {
        MyInterface myObject = new MyInterface() {};
        if (java.lang.Math.random() > 0.5)
            myObject = new B();
        A a = (A) myObject;
    }
}
like image 182
aioobe Avatar answered Jan 13 '23 03:01

aioobe


Java language specification states, that:

Some casts can be proven incorrect at compile time; such casts result in a compile-time error.

And later on the show The detailed rules for compile-time legality of a casting conversion of a value of compile-time reference type S to a compile-time reference type T - beware, they are very complex and hard to understand.

The interesting rule is:

  • If S is an interface type:
    • If T is a type that is not final (§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 T does not implement S, a subclass of T might).

In your example, it's perfectly clear, that the cast is illegal. But consider this slight change:

public class InterfaceCasting {

    private static class A{}
    private static class B extends A implements Serializable{}

    public static void main(String[] args) {
        A a = new A();
        Serializable serializable = new B(){};
        a = (A)serializable;
    }    
}

Now a cast from a Serializable to A is possible at runtime and this shows, that in those cases, it's better left to the runtime to decide if we can cast or not.

like image 34
Andreas Dolk Avatar answered Jan 13 '23 03:01

Andreas Dolk