Bird
Raised Fist0
Javaprogramming~10 mins

Upcasting and downcasting in Java - Step-by-Step Execution

Choose your learning style10 modes available

Start learning this pattern below

Jump into concepts and practice - no test required

or
Recommended
Test this pattern10 questions across easy, medium, and hard to know if this pattern is strong
Concept Flow - Upcasting and downcasting
Create Subclass Object
Upcast to Superclass Reference
Use Superclass Reference
Downcast to Subclass Reference
Use Subclass Reference
End
First, create an object of a subclass. Then, assign it to a superclass reference (upcasting). Later, convert back to subclass reference (downcasting) to access subclass-specific features.
Execution Sample
Java
class Animal {}
class Dog extends Animal {
  void bark() { System.out.println("Woof"); }
}
Animal a = new Dog(); // upcasting
((Dog) a).bark(); // downcasting
This code creates a Dog object, upcasts it to Animal, then downcasts back to Dog to call bark.
Execution Table
StepActionReference TypeObject TypeMethod CalledOutput
1Create Dog objectDogDogNoneNone
2Upcast Dog to AnimalAnimalDogNoneNone
3Call bark() via Animal reference (invalid)AnimalDogN/ACompile-time error if no cast
4Downcast Animal to DogDogDogNoneNone
5Call bark() via Dog referenceDogDogbark()Woof
💡 Execution ends after bark() prints 'Woof'.
Variable Tracker
VariableStartAfter Step 1After Step 2After Step 4Final
anullDog objectAnimal reference to Dog objectDog reference to Dog objectDog reference to Dog object
Key Moments - 3 Insights
Why can't we call bark() directly on the Animal reference?
Because the Animal class does not have the bark() method. The execution_table row 3 shows calling bark() on Animal reference causes a compile-time error without downcasting.
What does upcasting do to the reference type?
Upcasting changes the reference type to the superclass (Animal) but the actual object remains the subclass (Dog), as shown in execution_table row 2.
Why do we need downcasting before calling subclass methods?
Downcasting tells the compiler the reference is actually the subclass type, allowing access to subclass methods like bark(), as shown in execution_table rows 4 and 5.
Visual Quiz - 3 Questions
Test your understanding
Look at the execution_table, what is the reference type of variable 'a' after step 2?
ADog
BObject
CAnimal
DCannot determine
💡 Hint
Check the 'Reference Type' column at step 2 in execution_table.
At which step does the program actually print 'Woof'?
AStep 4
BStep 5
CStep 3
DStep 2
💡 Hint
Look at the 'Output' column in execution_table to find when 'Woof' is printed.
If we skip downcasting and call bark() on 'a' directly, what happens?
ACompile-time error
BRuntime error
CIt prints 'Woof' anyway
DNothing happens
💡 Hint
Refer to execution_table row 3 where calling bark() on Animal reference without cast is invalid.
Concept Snapshot
Upcasting: Assign subclass object to superclass reference.
Downcasting: Convert superclass reference back to subclass.
Upcasting is automatic; downcasting requires explicit cast.
Subclass methods need downcasting to be accessed.
Avoid ClassCastException by ensuring object type matches cast.
Full Transcript
This visual trace shows how upcasting and downcasting work in Java. First, a Dog object is created. Then it is upcast to an Animal reference, which means the reference type is Animal but the object is still Dog. You cannot call Dog-specific methods like bark() on the Animal reference directly. To call bark(), you must downcast the Animal reference back to Dog. This cast tells the compiler the reference is actually a Dog, allowing access to bark(). The execution table shows each step, including the reference and object types, and when the bark() method is called and prints 'Woof'. Key moments clarify why direct calls on the superclass reference fail and why casting is necessary. The quiz tests understanding of reference types, method calls, and errors without casting.

Practice

(1/5)
1. What is upcasting in Java?
Upcasting means:
easy
A. Changing the value of a variable
B. Treating a specific object as a more general type
C. Creating a new object from a class
D. Converting a general type to a specific type

Solution

  1. Step 1: Understand object type hierarchy

    In Java, classes can inherit from other classes, making some types more general (superclass) and others more specific (subclass).
  2. Step 2: Define upcasting

    Upcasting means treating a subclass object as if it were an instance of its superclass, which is more general.
  3. Final Answer:

    Treating a specific object as a more general type -> Option B
  4. Quick Check:

    Upcasting = Treat specific as general [OK]
Hint: Upcasting = subclass object as superclass type [OK]
Common Mistakes:
  • Confusing upcasting with downcasting
  • Thinking upcasting creates a new object
  • Believing upcasting changes the actual object type
2. Which of the following is the correct syntax for downcasting in Java?
Animal a = new Dog();
// Downcast here
easy
A. Dog d = (Dog) a;
B. Dog d = a;
C. Dog d = a.toDog();
D. Dog d = (Animal) a;

Solution

  1. Step 1: Understand downcasting syntax

    Downcasting requires an explicit cast to convert a superclass reference back to a subclass type.
  2. Step 2: Apply correct cast

    The correct syntax is: SubclassType var = (SubclassType) superClassVar; so here: Dog d = (Dog) a;
  3. Final Answer:

    Dog d = (Dog) a; -> Option A
  4. Quick Check:

    Downcasting needs explicit cast [OK]
Hint: Downcast with (Subclass) before variable [OK]
Common Mistakes:
  • Omitting the cast operator
  • Casting to wrong type
  • Using methods like toDog() which don't exist
3. What will be the output of this code?
class Animal { void sound() { System.out.println("Animal sound"); } }
class Dog extends Animal { void sound() { System.out.println("Bark"); } void fetch() { System.out.println("Fetching"); } }
public class Test {
  public static void main(String[] args) {
    Animal a = new Dog(); // upcasting
    a.sound();
    // a.fetch(); // line A
    ((Dog) a).fetch(); // line B
  }
}
medium
A. Bark\nFetching
B. Bark\nAnimal sound
C. Animal sound\nFetching
D. Compilation error at line A

Solution

  1. Step 1: Understand method overriding and upcasting

    Variable a is of type Animal but refers to a Dog object. Calling a.sound() calls Dog's overridden method, printing "Bark".
  2. Step 2: Analyze method call fetch()

    Method fetch() is not in Animal, so a.fetch() is invalid (commented out). Downcasting (Dog) a allows calling fetch(), printing "Fetching".
  3. Final Answer:

    Bark Fetching -> Option A
  4. Quick Check:

    Upcast calls overridden method, downcast calls subclass method [OK]
Hint: Upcast calls overridden; downcast needed for subclass-only methods [OK]
Common Mistakes:
  • Thinking a.sound() calls Animal's method
  • Trying to call fetch() without downcasting
  • Confusing compile vs runtime errors
4. Identify the error and fix it in this code:
class Animal {}
class Cat extends Animal { void meow() { System.out.println("Meow"); } }
public class Test {
  public static void main(String[] args) {
    Animal a = new Animal();
    Cat c = (Cat) a; // line X
    c.meow();
  }
}
medium
A. No error, code runs fine
B. Syntax error; fix by removing cast
C. ClassCastException at runtime; fix by checking instanceof before casting
D. Change Animal to Cat in line X

Solution

  1. Step 1: Identify the casting problem

    Variable a refers to an Animal object, not a Cat. Casting Animal to Cat without checking causes ClassCastException at runtime.
  2. Step 2: Fix with instanceof check

    Before casting, check if (a instanceof Cat) to ensure safe downcasting and avoid runtime error.
  3. Final Answer:

    ClassCastException at runtime; fix by checking instanceof before casting -> Option C
  4. Quick Check:

    Downcast only if instanceof true [OK]
Hint: Use instanceof before downcasting to avoid errors [OK]
Common Mistakes:
  • Ignoring runtime ClassCastException
  • Assuming cast always works
  • Trying to fix with syntax changes only
5. Given these classes:
class Vehicle { void start() { System.out.println("Vehicle started"); } }
class Car extends Vehicle { void start() { System.out.println("Car started"); } void openTrunk() { System.out.println("Trunk opened"); } }
class Bike extends Vehicle { void start() { System.out.println("Bike started"); } void kickStart() { System.out.println("Kickstarted"); } }

Which code snippet correctly upcasts and downcasts to call openTrunk() safely?
hard
A.
Vehicle v = new Vehicle();
if (v instanceof Car) {
  ((Car) v).openTrunk();
}
B.
Vehicle v = new Bike();
((Car) v).openTrunk();
C.
Car c = new Vehicle();
c.openTrunk();
D.
Vehicle v = new Car();
if (v instanceof Car) {
  ((Car) v).openTrunk();
}

Solution

  1. Step 1: Understand upcasting and downcasting here

    Variable v is declared as Vehicle but assigned a Car object (upcasting). To call Car-specific method openTrunk(), downcast is needed.
  2. Step 2: Check safe downcasting

    Using instanceof ensures v is actually a Car before downcasting and calling openTrunk(). This avoids runtime errors.
  3. Final Answer:

    Vehicle v = new Car(); if (v instanceof Car) { ((Car) v).openTrunk(); } -> Option D
  4. Quick Check:

    Upcast then instanceof check before downcast [OK]
Hint: Always check instanceof before downcasting [OK]
Common Mistakes:
  • Downcasting without instanceof check
  • Assigning superclass object to subclass variable
  • Calling subclass methods on superclass references without cast