Search code examples
javacastingtype-narrowing

Java Narrowing Reference Conversion from a type to an interface


Trying to understand java narrowing conversion from a class to an interface. The JLS(JLS-5.1.6) states:

From any class type C to any non-parameterized interface type K, provided that C is not final and does not implement K.

To test this, I created a class and an interface. Then tried casting the class to the interface, but get a run-time ClassCastException. This is a sample of my code.

class NarrowingReferenceConversion
{
    public static void main(String args[])
    {

        S s = new S();
        T t = (T)s;

    }
}

interface T
{
    public void print();
}

class S
{
    public void print(){
        System.out.println("S.print()");
    }
}

On compiling and running the above I get the following error message:

Exception in thread "main" java.lang.ClassCastException: S cannot be cast to T


Solution

  • This is a conversion that is not guaranteed to work, just like casting a reference of a base class to a sub-class is not guaranteed to work. That's why it is considered a narrowing conversion.

    The compiler knows that the conversion might work at runtime, so it allows it, but if it doesn't work, ClassCastException is thrown at runtime.

    Only if you assign to s an instance of a sub-class of S that does implement the interface T, the conversion will work.

    class NarrowingReferenceConversion
    {
        public static void main(String args[])
        {
    
            S s = new S2();
            T t = (T) s; // this will work, since S2 implements T
    
        }
    }
    
    interface T
    {
        public void print();
    }
    
    class S
    {
        public void print(){
            System.out.println("S.print()");
        }
    }
    
    class S2 extends S implements T
    {
    }
    

    Let's explain the two conditions of this conversion:

    1. "C is not final" - if it was final, there would be no sub-classes of C, so the compiler knows for sure this conversion can never work, and compilation fails.

    2. "does not implement K" - if C implements K, this is no longer a narrowing conversion. It becomes a Widening Reference Conversion, guaranteed to succeed at runtime. In fact, there would be no need to use the cast operator. A simple assignment will do.