Casting Between Class-Interface and Interface-Interface

People who are new to Java, sometimes get confused as to why a cast between a reference of an unrelated class and interface is allowed. This is what we’ll discuss in this tutorial.

Casting-Between-Class-Interface-and-Interface-Interface

Check the code below,

interface MyInterface{}
class MyClass{}
class Main {
    public static void main(String[] args) {
        MyClass obj = new MyClass();
        MyInterface iObj = (MyInterface)obj;  //compiles fine
    }
}

You are probably thinking that is cast will result in a ClassCastException at runtime. We know that the cast will fail at run time then why does the compiler allows it? The reason the cast is allowed is because the compiler thinks the cast might be successful at runtime. As we know a class is allowed to extend another class and implement any number of interfaces. So there can be a class which extends MyClass and implements MyInterface. This is why the cast is allowed. Like the following code will compile and run fine

interface MyInterface{}
class MyClass{}
class MySubClass extends MyClass implements MyInterface
class Main {
    public static void main(String[] args) {
        MyClass obj = new MySubClass();
        MyInterface iObj = (MyInterface)obj;  //compiles and runs fine
    }
}

But the cast was compiling even when we didn’t create any class which is a subclass of MyClass and MyInterface. We didn’t create such a class doesn’t mean that such a class cannot be created in the future! Lets take an example from the Java API. Thread class doesn’t implement Serializable. Still the following code will compile without any error,

public static void main(String[] args){
    Thread t = new Thread();
    Serializable s = (Serializable)t;  //compiles fine
}

The reason it compiles without any error is that I might create a class which extends Thread and implements Serializable*. The compiler cannot check what object t actually points to, so it cannot tell whether the cast will be successful or not. Basically when it comes to the cast, this is the code that the compiler sees

public static void main(String[] args){
    Thread t = XXXXXXXXXXXX;
    Serializable s = (Serializable)t;  //compiles fine
}

What the compiler says to itself is, “Okay so t is a reference of type Thread. I don’t know what will be the exact type of t at runtime. So I’ll have to allow the cast to Serializable as t might point to an object which is both a Thread and Serializable” Because of this, a cast between a class and interface OR interface and interface is always allowed.

There is one exception to this rule. A cast between unrelated final class and interface is not allowed. Thus the following code will fail to compile,

interface MyInterface{}
final class MyClass{}
class Main {
    public static void main(String[] args) {
        MyClass obj = new MyClass();
        MyInterface iObj = (MyInterface)obj;  //compiler error
    }
}

The reason the cast fails this time is because MyClass is final, so the compiler knows that there cannot be any class which extends MyClass and implements MyInterface (as MyClass cannot be subclassed). So the compiler knows that the cast cannot succeed at runtime. This is why the compiler disallows the cast.

*Note that a Serializable Thread isn’t a very good idea, this is used here just for demonstration purpose.