java.lang.ClassException: A cannot be cast into B
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.
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 variablea
so it needs to generate code which will be safe for all possible values. If compiler wouldn't complain aboutB1 b = a;
it should also allow to compileB2 b = a;
. So just to be safe it doesn't let us do it.So what should we do to assign reference from
a
toB1
? We need to explicitly tell compiler that we are aware of potential type mismatch issue here, but we are sure that reference held ina
can be safely assigned in variable of typeB
. We do so by casting value froma
to typeB
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
.