Return to site
[VV121] The Java 21 Newsletter: 🔼 Upcasting and 🔽 Downcasting (Subcasting)
[VV121] The Java 21 Newsletter: 🔼 Upcasting and 🔽 Downcasting (Subcasting)
·
🔼 Upcasting
- Definition: Casting a subclass object to a superclass type.
- Safe: Always safe, no explicit cast required.
- What is accessible: Only the declared type’s methods/fields (superclass), unless overridden.
class Animal { void speak() { System.out.println("Animal speaks"); } } class Dog extends Animal { void speak() { System.out.println("Dog barks"); } void fetch() { System.out.println("Dog fetches"); } } public class Main { public static void main(String[] args) { Animal a = new Dog(); // Upcasting a.speak(); // "Dog barks" -> dynamic dispatch (method overriding) // a.fetch(); ❌ Compile error (not in Animal) } }
Key Point:
- ✅ Methods are determined at runtime → actual object's type (Dog) decides what method is executed (polymorphism).
- ❌ Attributes/fields (if any) are not polymorphic → they are resolved at compile-time using the declared type.
🔽 Downcasting (Subcasting)
- Definition: Casting a superclass object to a subclass type.
- Risky: Must be done explicitly, and it can throw a ClassCastException if not valid.
- What is accessible: After downcasting, you can access the subclass-specific methods/fields.
Animal a = new Dog(); // Upcasting Dog d = (Dog) a; // Downcasting d.fetch(); // "Dog fetches" ✅ now accessible
Wrong downcast example:
Animal a = new Animal(); Dog d = (Dog) a; // ❌ Runtime error: ClassCastException
🔧 Summary Table

🔍 Real Example with Field
class Animal { String type = "Generic Animal"; void speak() { System.out.println("Animal speaks"); } } class Dog extends Animal { String type = "Dog"; void speak() { System.out.println("Dog barks"); } } public class Main { public static void main(String[] args) { Animal a = new Dog(); System.out.println(a.type); // "Generic Animal" – resolved by declared type a.speak(); // "Dog barks" – resolved by actual type } }
🎢 Mental Model: Think of a Class Hierarchy as a Tree
Object
Object
↑
Animal
↑
Dog- The top of the tree is more general (Object, Animal)
- The bottom of the tree is more specific (Dog, Poodle, etc.)
🔼 Upcasting = Going up the hierarchy
- From specific to general (e.g., Dog → Animal)
- Safe, because a Dog is always an Animal
- Loses access to specific features
🔽 Downcasting = Going down the hierarchy
- From general to specific (e.g., Animal → Dog)
- Risky, because not all Animals are Dogs
- Gains access to subclass features, but only if valid
🧠 How to Remember
Try one of these mnemonics:
1. "Upcasting climbs the tree, downcasting dives deep."
- Imagine the class hierarchy as a vertical structure (like a tree or org chart).
- "Up" means more general (e.g., to Animal or Object)
- "Down" means more specific (e.g., to Dog)
2. Think in terms of "zoom level":
- Upcasting = zooming out → you see less detail (fewer features)
- Downcasting = zooming in → you see more detail (more features, but may not always be safe)
3. Java's automatic vs. manual:
- Upcasting = automatic (Java does it for you)
- Downcasting = manual (you have to tell Java: Dog d = (Dog) a;)
🧪 Example Recap
Dog d = new Dog(); Animal a = d; // ✅ Upcasting (automatic) Dog d2 = (Dog) a; // ✅ Downcasting (manual, but safe here) Animal a2 = new Animal(); Dog d3 = (Dog) a2; // ❌ Runtime error: ClassCastException
Upcasting: Dog → Animal (safe, general)
Downcasting: Animal → Dog (risky, specific)
Upcasting: Dog → Animal (safe, general)
Downcasting: Animal → Dog (risky, specific)