Java > Object-Oriented Programming (OOP) > Polymorphism > Upcasting and Downcasting
Upcasting and Downcasting in Java Polymorphism
This example demonstrates upcasting and downcasting in Java, illustrating how they are used within the context of polymorphism to manipulate objects of different classes through a common superclass reference.
Code Example
This code defines three classes: `Animal`, `Dog`, and `Cat`. `Dog` and `Cat` are subclasses of `Animal`. The `makeSound()` method is overridden in both subclasses. The `main` method demonstrates upcasting (assigning a `Dog` object to an `Animal` reference) and downcasting (converting an `Animal` reference back to a `Dog` reference). The `instanceof` operator is used to safely check the type before downcasting to avoid `ClassCastException`.
class Animal {
public void makeSound() {
System.out.println("Generic animal sound");
}
}
class Dog extends Animal {
public void makeSound() {
System.out.println("Woof!");
}
public void fetch() {
System.out.println("Fetching the ball!");
}
}
class Cat extends Animal {
public void makeSound() {
System.out.println("Meow!");
}
public void scratch() {
System.out.println("Scratching the furniture!");
}
}
public class CastingExample {
public static void main(String[] args) {
// Upcasting: Creating a Dog object and assigning it to an Animal reference
Animal animal1 = new Dog(); // Implicit upcasting
animal1.makeSound(); // Calls Dog's makeSound() - Polymorphism in action
// Downcasting: Converting an Animal reference back to a Dog reference
if (animal1 instanceof Dog) {
Dog myDog = (Dog) animal1; // Explicit downcasting
myDog.fetch(); // Calls Dog's fetch() method
}
// Example with Cat
Animal animal2 = new Cat();
animal2.makeSound(); // Calls Cat's makeSound()
//Attempting unsafe downcast
if (animal2 instanceof Dog) {
Dog myDog = (Dog) animal2; // Throws ClassCastException if animal2 is not a Dog
myDog.fetch(); // compilation error if the if statement doesn't exist.
} else {
System.out.println("animal2 is not a Dog, so cannot downcast.");
}
}
}
Concepts Behind the Snippet
Real-Life Use Case
Consider a GUI application with various UI components like buttons, text fields, and labels, all inheriting from a base `Component` class. You might have a list of `Component` objects (upcasting). To perform a specific action unique to a `Button` (e.g., set its click listener), you would need to downcast a `Component` from the list to a `Button`, first ensuring it's actually a `Button` using `instanceof`.
Best Practices
Interview Tip
Be prepared to explain the difference between upcasting and downcasting, why downcasting requires explicit casting and can be unsafe, and how `instanceof` helps prevent errors. Also, be ready to discuss the role of polymorphism in enabling these concepts.
When to Use Them
Memory Footprint
Upcasting and downcasting themselves don't directly impact memory footprint. The objects themselves occupy the same amount of memory regardless of whether they are referenced by a superclass or subclass type. However, excessive creation of objects and the associated memory management remain important considerations.
Alternatives
Pros
Cons
FAQ
-
What happens if I try to downcast an object to a class it isn't an instance of?
A `ClassCastException` will be thrown at runtime. This is why it's crucial to use the `instanceof` operator to check the object's type before downcasting. -
Why is upcasting implicit, but downcasting explicit?
Upcasting is implicit because a subclass object 'is-a' superclass object. There's no loss of information. Downcasting, on the other hand, requires explicit casting because a superclass object is not necessarily a subclass object. It's a potentially unsafe operation that the programmer needs to acknowledge. -
Can I downcast to a class that is not directly related to the object's actual class?
No. You can only downcast to a type that the object actually is or is a supertype of. For example, if you have an `Animal` object that is actually a `Dog`, you can downcast it to `Dog`. You cannot downcast it to `Cat`.