I implemented this code:
class A {
//some code
}
class B extends A {
// some code
}
class C {
public static void main(String []args)
{
Because, all the compiler sees is that an A is cast into a B. Since some A's can actually be B's this may work for those A's. By writing the explicit cast, you ensure that this particular A is actually a valid B. However, this is not the case.
A justA = new A();
A anAThatIsAlsoAValidB = new B(); // implicit cast to supertype
B b1 = (A) anAThatIsAlsoAValidB ; // Cast an A into a B. At runtime, this will work fine! Compiler allows casting A into B.
B b2 = (A) justA; // Cast an A into a B. At runtime, this won't work. Compiler has/uses no more info than above.
Here's why the compiler does not really know about the type:
com.example.ThridPartyType obj = new com.example.ThridPartyType();
B b = (B) obj.getSomeA();
// getSomeA() returns A and that is all the compiler knows.
// Depeding on the implementation of "ThridPartyType::getSomeA()" the A returned may or may not actually also be a valid B.
// Hence, if the cast works or not will only be known at runtime. If it doesn't, the Exception is thrown.
Has to do with when casting is done. You are telling the compiler: "Hey, don't worry about it, this is what I say it is, if you have a problem, take it up with me at runtime."
Basically, the compiler is letting you do your thing. When you explicitly cast something, the compiler doesn't do checks. When you run, and the program tries to cast but fails, that's when you will see the error.
A a1 = (B) new A();
Because A
is NOT B
.
Compile time works because you are casting and explicitly guaranteeing compiler that you are sure at runtime A
will be B
.
Following is a compiletime casting -
A a = new B();
Such static castings are implicitly performed by the compiler, because the compiler is aware of the fact that B is-a A.
Following doesn't compile -
B b = new A();
No compiletime casting here because the compiler knows that A is not B.
Following compiles -
B b = (B) new A();
It is a dynamic casting. With (B)
you are telling the compiler explicitly that you want the casting to happen at runtime. And you get a CCE at runtime, when the runtime tries to perform the cast but finds out that it cannot be done and throws a CCE.
When you do (or have to do) something like this, the responsibility falls upon you (not the compiler) to make sure that a CCE doesn't occur at runtime.
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.
Because the A
is a parent of B
. B
extends the functionality of the A
but keeps the original functionality of A
. So B
can in fact be cast to A
, but not vice versa.
What if B
added a new method, let's say newMethodInB()
. If you would try to call that method through variable B
on the instance A
(imagine that the cast worked) what would you expect? Well, you would definitely get an error because that method does not exist in A
.