Search code examples
javainheritance

java.lang.ClassException: A cannot be cast into B


I implemented this code:

class A {
    //some code
}
class B extends A {
    // some code
}

class C {
    public static void main(String []args)
    {
        B b1 = (B) new A();
        A a1 = (B) new A();
    }
}

Both of these lines, when compiled separately, compile fine,but give runtime error with java.lang.ClassException: A cannot be cast into B.

Why they compile well, but give a runtime error?


Solution

  • Variables of type A can store references to objects of type A or its subtypes like in your case class B.

    So it is possible to have code like:

    A a = new B();
    

    Variable a is of type A so it have only access to API of that class, it can't access methods added in class B which object it refers to. But sometimes we want to be able to access those methods so it should be possible to somehow store reference from a in some variable of more accurate type (here B) via which we would be able to access those additional methods from class B.
    BUT HOW CAN WE DO THAT?

    Lets try to achieve it this way:

    B b = a;//WRONG!!! "Type mismatch" error
    

    Such code gives compile time Type mismatch error. It happens to save us from situation like this:

    • class B1 extends A
    • class B2 extends A

      and we have A a = new B1();.

      Now lets try to assign B1 b = a;. Remember that compiler doesn't know what actually is held under variable a so it needs to generate code which will be safe for all possible values. If compiler wouldn't complain about B1 b = a; it should also allow to compile B2 b = a;. So just to be safe it doesn't let us do it.

      So what should we do to assign reference from a to B1? We need to explicitly tell compiler that we are aware of potential type mismatch issue here, but we are sure that reference held in a can be safely assigned in variable of type B. We do so by casting value from a to type B via (B)a.

      B b = (B)a;
      

    But lets go back to example from your question

    B b1 = (B) new A();
    A a1 = (B) new A();
    

    new operator returns reference of the same type as created object, so new A() returns reference of the type A so

    B b1 = (B) new A();
    

    can be seen as

    A tmp = new A();
    B b1 = (B) tmp;
    

    Problem here is that you can't store reference to object of superclass in variable of its derived type.
    Why such limitation exist? Lets say that derived class adds some new methods that supertype doesn't have like

    class A {
        // some code
    }
    
    class B extends A {
        private int i;
        public void setI(int i){
            this.i=i;
        }
    }
    

    If this would be allowed

    B b = (B)new A();
    

    you could later end up with invoking b.setI(42);. But will it be correct? No because instance of class A doesn't have method setI nor field i which that method uses.

    So to prevent such situation (B)new A(); at runtime throws java.lang.ClassCastException.