Elaborating the answer given by Michael Berry.
Dog d = (Dog)Animal; //Compiles but fails at runtime
Here you are saying to the compiler "Trust me. I know d
is really referring to a Dog
object" although it's not.
Remember compiler is forced to trust us when we do a downcast.
The compiler only knows about the declared reference type. The JVM at runtime knows what the object really is.
So when the JVM at the runtime figures out that the Dog d
is actually referring to an Animal
and not a Dog
object it says.
Hey... you lied to the compiler and throws a big fat ClassCastException
.
So if you are downcasting you should use instanceof
test to avoid screwing up.
if (animal instanceof Dog) {
Dog dog = (Dog) animal;
}
Now a question comes to our mind. Why the hell compiler is allowing the downcast when eventually it is going to throw a java.lang.ClassCastException
?
The answer is that all the compiler can do is verify that the two types are in the same inheritance tree, so depending on whatever code might have
come before the downcast, it's possible that animal
is of type dog
.
The compiler must allow things that might possible work at runtime.
Consider the following code snipet:
public static void main(String[] args)
{
Dog d = getMeAnAnimal();// ERROR: Type mismatch: cannot convert Animal to Dog
Dog d = (Dog)getMeAnAnimal(); // Downcast works fine. No ClassCastException :)
d.eat();
}
private static Animal getMeAnAnimal()
{
Animal animal = new Dog();
return animal;
}
However, if the compiler is sure that the cast would not possible work, compilation will fail. I.E. If you try to cast objects in different inheritance hierarchies
String s = (String)d; // ERROR : cannot cast for Dog to String
Unlike downcasting, upcasting works implicitly because when you upcast you are implicitly restricting the number of method you can invoke,
as opposite to downcasting, which implies that later on, you might want to invoke a more specific method.
Dog d = new Dog();
Animal animal1 = d; // Works fine with no explicit cast
Animal animal2 = (Animal) d; // Works fine with n explicit cast
Both of the above upcast will work fine without any exception because a Dog IS-A Animal, anithing an Animal can do, a dog can do. But it's not true vica-versa.