Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 534
Ozil Avatar asked Jun 20 '13 15:06

Ozil


People also ask

How do I resolve Java Lang ClassCastException error?

How to handle ClassCastException. To prevent the ClassCastException exception, one should be careful when casting objects to a specific class or interface and ensure that the target type is a child of the source type, and that the actual object is an instance of that type.

What causes ClassCastException in Java?

Introduction. ClassCastException is a runtime exception raised in Java when we try to improperly cast a class from one type to another. It's thrown to indicate that the code has attempted to cast an object to a related class, but of which it is not an instance.

What is ClassCastException in Java with example?

Straight from the API Specifications for the ClassCastException : Thrown to indicate that the code has attempted to cast an object to a subclass of which it is not an instance. So, for example, when one tries to cast an Integer to a String , String is not an subclass of Integer , so a ClassCastException will be thrown.


2 Answers

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.

like image 50
Pshemo Avatar answered Nov 04 '22 06:11

Pshemo


The reason it fails at runtime is that the object isn't a B. It's an A. So while some As can be casts as Bs, yours cannot.

The compilier just can't analyze everything that happened to your A object. For example.

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

B b1 = (B) a1;    // Ok
B b2 = (B) a2;    // Fails

So the compilier isn't sure whether your A object is actually castable to a B. So in the above, it would think that the last 2 lines were ok. But when you actually run the program, it realizes that a2 is not a B, it's only an A.

like image 38
Snowy Coder Girl Avatar answered Nov 04 '22 05:11

Snowy Coder Girl