What are upcasting and downcasting in Java, and which one does the compiler do for you?
An upcast converts a reference to a subtype into a reference to a supertype. A downcast converts a reference to a supertype back into one to a subtype.
Upcasting is always safe and is always implicit. Every Dog is an Animal, so assigning a Dog reference to an Animal variable needs no cast and no annotation. The compiler allows it because the relationship is guaranteed by the type system, and the runtime type of the object does not change — the object is still a Dog, it is simply being referred to through a less specific type.
Downcasting is the reverse and it is explicit, because the compiler cannot know whether the object really is the subtype. If you hold an Animal reference that actually points at a Dog, the downcast succeeds and gives you a Dog reference. If it points at a Cat, the cast throws ClassCastException at run time. The cast is a promise you make to the compiler, and the JVM checks the promise when it executes.
public class Main {
public static void main(String[] args) {
// Upcasting: widening reference conversion, always safe, implicit.
Animal animal = new Dog();
System.out.println("upcast : " + animal.speak());
// Downcasting: narrowing, needs an explicit cast.
Dog dog = (Dog) animal;
System.out.println("downcast : " + dog.fetch());
// The runtime type never changes, only the reference's view of it.
System.out.println("runtime : " + animal.getClass().getSimpleName());
}
}
class Animal {
String speak() {
return "...";
}
}
class Dog extends Animal {
@Override
String speak() {
return "woof";
}
String fetch() {
return "fetching the ball";
}
}The output shows the three things that matter. The upcast compiles with no ceremony. The downcast lets you call the Dog-specific method. And the runtime type is still Dog even after the upcast, which is why the downcast succeeds and why polymorphic dispatch still calls the Dog implementation of speak.
The one case where a downcast is not needed is a cast to the same type, or a cast to Object — but that is just an upcast, and it is written without parentheses.