Bird
Raised Fist0
Javaprogramming~15 mins

Runtime polymorphism in Java - Deep Dive

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
Overview - Runtime polymorphism
What is it?
Runtime polymorphism in Java means that the program decides which method to call while it is running, not when it is compiled. It happens when a subclass provides a specific version of a method that is already defined in its parent class. This allows one object to behave differently depending on its actual type during execution. It helps write flexible and reusable code.
Why it matters
Without runtime polymorphism, programs would be rigid and repetitive because every object would only use methods defined exactly for its type. It solves the problem of needing many similar methods for different types by letting one method call work for many types. This makes programs easier to extend and maintain, saving time and reducing errors.
Where it fits
Before learning runtime polymorphism, you should understand classes, objects, inheritance, and method overriding in Java. After mastering runtime polymorphism, you can explore design patterns like Strategy or Template Method, and advanced topics like dynamic proxies and reflection.
Mental Model
Core Idea
Runtime polymorphism lets a program choose the right method version to run based on the actual object type during execution.
Think of it like...
It's like a universal remote that can control many devices; pressing the same button sends a command, but the device decides how to respond based on what it is.
┌───────────────┐
│ Parent Class  │
│ method()      │
└──────┬────────┘
       │ overridden by
┌──────▼────────┐
│ Child Class   │
│ method()      │
└──────┬────────┘
       │
       ▼
At runtime, the actual object's method() is called, not the reference type's.
Build-Up - 7 Steps
1
FoundationUnderstanding Classes and Objects
🤔
Concept: Learn what classes and objects are in Java as the building blocks of polymorphism.
A class is like a blueprint for creating objects. An object is an instance of a class with its own data. For example, a class Car can create many car objects, each with its own color and model.
Result
You can create objects from classes and use their methods and data.
Understanding classes and objects is essential because polymorphism works by calling methods on objects created from classes.
2
FoundationBasics of Inheritance
🤔
Concept: Inheritance lets one class reuse code from another by extending it.
In Java, a class can inherit from another class using the 'extends' keyword. The child class gets all the methods and fields of the parent class and can add or change them.
Result
You can create a new class that shares behavior with an existing class, reducing code duplication.
Inheritance sets the stage for polymorphism by creating a family of related classes with shared behavior.
3
IntermediateMethod Overriding Explained
🤔
Concept: Method overriding allows a child class to provide its own version of a method defined in the parent class.
If a parent class has a method called 'display()', the child class can write its own 'display()' method with different behavior. When called on a child object, the child's method runs instead of the parent's.
Result
Child objects can behave differently even when accessed through a parent class reference.
Overriding is the key mechanism that enables runtime polymorphism by changing method behavior in subclasses.
4
IntermediateUsing Parent References for Child Objects
🤔Before reading on: Do you think a parent class reference can call child class methods directly? Commit to your answer.
Concept: A parent class reference can point to a child class object, enabling polymorphism.
You can write code like 'Parent p = new Child();'. When you call an overridden method on 'p', Java decides at runtime which version to run based on the actual object type (Child).
Result
The program calls the child's method even if the reference is of the parent type.
Knowing that references can point to child objects is crucial for understanding how runtime polymorphism works in practice.
5
IntermediateDynamic Method Dispatch Mechanism
🤔Before reading on: Does Java decide which method to call at compile time or runtime? Commit to your answer.
Concept: Java uses dynamic method dispatch to select the method implementation at runtime.
When a method is called on a parent reference, Java looks up the actual object's class at runtime and calls the overridden method there. This is called dynamic dispatch.
Result
The correct method version runs depending on the object's real type, not the reference type.
Understanding dynamic dispatch explains how Java achieves flexible method calls and supports polymorphism.
6
AdvancedRuntime Polymorphism with Abstract Classes
🤔Before reading on: Can abstract classes participate in runtime polymorphism? Commit to your answer.
Concept: Abstract classes can define methods without implementation that subclasses must override, enabling polymorphism.
An abstract class can have abstract methods. Subclasses provide concrete implementations. When you use a parent abstract class reference, calling these methods runs the subclass version at runtime.
Result
You can write flexible code that works with many subclasses through a common abstract parent.
Using abstract classes with runtime polymorphism enforces a contract for subclasses and improves code design.
7
ExpertPerformance and Limitations of Runtime Polymorphism
🤔Before reading on: Does runtime polymorphism slow down method calls significantly? Commit to your answer.
Concept: Runtime polymorphism adds a small overhead due to method lookup but enables powerful design patterns.
At runtime, Java uses a method table to find the correct method, which is slightly slower than direct calls. Also, final methods cannot be overridden, so they don't support polymorphism. Understanding these helps write efficient and correct code.
Result
You balance flexibility with performance and know when polymorphism applies.
Knowing the cost and limits of runtime polymorphism helps avoid misuse and optimize critical code.
Under the Hood
Java uses a method table (vtable) for each class that stores pointers to method implementations. When a method is called on an object, the JVM looks up the object's class vtable at runtime to find the correct method to execute. This lookup enables dynamic dispatch, allowing overridden methods in subclasses to be called even when accessed through a parent class reference.
Why designed this way?
This design allows Java to support flexible and extensible code where behavior can change dynamically without recompiling. Early binding (compile-time method selection) would limit this flexibility. The tradeoff is a small runtime cost for method lookup, but it enables powerful object-oriented designs.
┌───────────────┐
│ Object o      │
│ Class: Child  │
└──────┬────────┘
       │
       ▼
┌───────────────┐
│ Child vtable  │
│ method() → Child.method()  │
└───────────────┘
       │
       ▼
┌───────────────┐
│ JVM calls     │
│ Child.method()│
└───────────────┘
Myth Busters - 4 Common Misconceptions
Quick: Does runtime polymorphism mean the compiler decides which method to call? Commit to yes or no.
Common Belief:Many think the compiler decides which method runs based on the reference type.
Tap to reveal reality
Reality:The JVM decides at runtime which overridden method to call based on the actual object's class.
Why it matters:Believing compile-time decision leads to confusion about why child methods run when using parent references.
Quick: Can static methods be overridden and participate in runtime polymorphism? Commit to yes or no.
Common Belief:Some believe static methods behave like instance methods and can be overridden.
Tap to reveal reality
Reality:Static methods belong to the class, not instances, so they cannot be overridden or dispatched at runtime.
Why it matters:Misusing static methods expecting polymorphism causes bugs where the parent class method always runs.
Quick: Does runtime polymorphism work with private methods? Commit to yes or no.
Common Belief:People often think private methods can be overridden and participate in polymorphism.
Tap to reveal reality
Reality:Private methods are not visible to subclasses and cannot be overridden; they are bound at compile time.
Why it matters:Expecting polymorphic behavior with private methods leads to unexpected method calls and bugs.
Quick: Is runtime polymorphism always slower and should be avoided? Commit to yes or no.
Common Belief:Some think runtime polymorphism causes significant performance issues and should be avoided.
Tap to reveal reality
Reality:The overhead is minimal and usually negligible compared to the benefits of flexible design.
Why it matters:Avoiding polymorphism unnecessarily can lead to rigid, hard-to-maintain code.
Expert Zone
1
Overriding equals() and hashCode() methods affects polymorphic behavior in collections and comparisons.
2
The final keyword prevents overriding, so methods marked final do not participate in runtime polymorphism.
3
Bridge methods generated by the compiler help maintain polymorphism with generics and type erasure.
When NOT to use
Avoid runtime polymorphism when performance is critical and method calls are in tight loops; consider using final methods or static dispatch. Also, if behavior does not need to change dynamically, simple inheritance or composition may be clearer.
Production Patterns
Runtime polymorphism is widely used in frameworks like Spring for dependency injection, in GUI event handling where listeners override base methods, and in design patterns such as Strategy and State to switch behavior at runtime.
Connections
Dynamic Dispatch in Compilers
Runtime polymorphism in Java is an example of dynamic dispatch, a concept used in many programming languages and compiler designs.
Understanding Java's runtime polymorphism helps grasp how compilers and runtimes decide method calls dynamically in other languages too.
Behavioral Design Patterns
Runtime polymorphism enables design patterns like Strategy and State that rely on changing behavior at runtime.
Knowing polymorphism deepens understanding of how these patterns achieve flexibility and extensibility.
Human Decision Making
Runtime polymorphism is like how humans choose actions based on context and identity at the moment, not just fixed rules.
This connection shows how programming models can mimic flexible, context-aware decision processes in real life.
Common Pitfalls
#1Calling a method on a parent reference expecting child-specific methods to run without overriding.
Wrong approach:Parent p = new Child(); p.childOnlyMethod(); // Error: method not in Parent
Correct approach:Child c = new Child(); c.childOnlyMethod(); // Works because reference is Child
Root cause:Trying to call methods not declared in the parent class on a parent reference causes compile errors.
#2Using static methods expecting polymorphic behavior.
Wrong approach:Parent p = new Child(); p.staticMethod(); // Calls Parent's staticMethod, not Child's
Correct approach:Child.staticMethod(); // Calls Child's staticMethod directly
Root cause:Static methods belong to classes, not instances, so they do not override or dispatch polymorphically.
#3Marking methods as final and expecting them to be overridden.
Wrong approach:class Parent { final void method() {} } class Child extends Parent { void method() {} // Compile error }
Correct approach:Remove final keyword to allow overriding: class Parent { void method() {} }
Root cause:Final methods cannot be overridden, so polymorphism does not apply.
Key Takeaways
Runtime polymorphism lets Java decide which method to run based on the actual object's type during program execution.
It relies on method overriding and parent class references pointing to child objects to enable flexible behavior.
Dynamic method dispatch is the mechanism that makes runtime polymorphism possible by looking up methods at runtime.
Understanding its limits, like static and final methods not supporting polymorphism, prevents common bugs.
Runtime polymorphism is a foundation for many design patterns and flexible software architectures.

Practice

(1/5)
1. What is runtime polymorphism in Java?
easy
A. Creating multiple objects of the same class
B. Using multiple classes with the same name
C. Choosing which method to call during program execution based on object type
D. Writing methods with different names in the same class

Solution

  1. Step 1: Understand polymorphism concept

    Polymorphism means many forms; in Java, it allows methods to behave differently based on object type.
  2. Step 2: Identify runtime polymorphism

    Runtime polymorphism happens when the program decides which overridden method to call during execution, not before.
  3. Final Answer:

    Choosing which method to call during program execution based on object type -> Option C
  4. Quick Check:

    Runtime polymorphism = method choice at runtime [OK]
Hint: Runtime polymorphism means method choice happens while running [OK]
Common Mistakes:
  • Confusing compile-time and runtime polymorphism
  • Thinking it means multiple classes with same name
  • Believing it is about method overloading
2. Which syntax correctly shows method overriding for runtime polymorphism in Java?
easy
A. class Parent { void show() {} } class Child extends Parent { void show() {} }
B. class Parent { void show() {} } class Child extends Parent { void display() {} }
C. class Parent { void show() {} } class Child { void show() {} }
D. class Parent { void show() {} } class Child extends Parent { void show(int x) {} }

Solution

  1. Step 1: Check method overriding rules

    Method overriding requires same method name and parameters in subclass extending superclass.
  2. Step 2: Match options with overriding

    class Parent { void show() {} } class Child extends Parent { void show() {} } shows subclass overriding show() method correctly; others differ in method name or parameters.
  3. Final Answer:

    class Parent { void show() {} } class Child extends Parent { void show() {} } -> Option A
  4. Quick Check:

    Same method name and parameters in subclass = overriding [OK]
Hint: Overriding needs same method name and parameters in subclass [OK]
Common Mistakes:
  • Changing method name in subclass instead of overriding
  • Changing method parameters (overloading, not overriding)
  • Not extending the parent class
3. What is the output of this code?
class Animal {
  void sound() { System.out.println("Animal sound"); }
}
class Dog extends Animal {
  void sound() { System.out.println("Bark"); }
}
public class Test {
  public static void main(String[] args) {
    Animal a = new Dog();
    a.sound();
  }
}
medium
A. Bark
B. Animal sound
C. Compilation error
D. Runtime error

Solution

  1. Step 1: Understand object and reference types

    Reference is of type Animal, but object is Dog, so overridden method in Dog is called.
  2. Step 2: Identify method called at runtime

    Due to runtime polymorphism, sound() of Dog runs, printing "Bark".
  3. Final Answer:

    Bark -> Option A
  4. Quick Check:

    Overridden method runs based on object type [OK]
Hint: Method called depends on object type, not reference type [OK]
Common Mistakes:
  • Thinking reference type decides method called
  • Expecting superclass method output
  • Confusing compile-time and runtime behavior
4. Find the error in this code related to runtime polymorphism:
class Parent {
  void show() { System.out.println("Parent"); }
}
class Child extends Parent {
  void show(int x) { System.out.println("Child " + x); }
}
public class Test {
  public static void main(String[] args) {
    Parent p = new Child();
    p.show();
  }
}
medium
A. Parent class method show() is private
B. Child class does not override show() method correctly
C. Cannot assign Child object to Parent reference
D. Missing main method

Solution

  1. Step 1: Check method overriding in Child class

    Child defines show(int x), which is overloading, not overriding show().
  2. Step 2: Understand method call on Parent reference

    Parent reference calls show() with no arguments, but Child has no overriding method, so Parent's method runs.
  3. Final Answer:

    Child class does not override show() method correctly -> Option B
  4. Quick Check:

    Overriding needs exact method signature match [OK]
Hint: Overriding needs same method signature, not just same name [OK]
Common Mistakes:
  • Thinking overloading is overriding
  • Expecting Child's show(int) to override show()
  • Ignoring method parameters in overriding
5. Given these classes:
class Vehicle {
  void start() { System.out.println("Vehicle starts"); }
}
class Car extends Vehicle {
  void start() { System.out.println("Car starts"); }
}
class Bike extends Vehicle {
  void start() { System.out.println("Bike starts"); }
}
public class Test {
  public static void main(String[] args) {
    Vehicle[] vehicles = {new Car(), new Bike(), new Vehicle()};
    for (Vehicle v : vehicles) {
      v.start();
    }
  }
}

What is the output when this program runs?
hard
A. Vehicle starts Vehicle starts Vehicle starts
B. Compilation error due to array initialization
C. Car starts Vehicle starts Bike starts
D. Car starts Bike starts Vehicle starts

Solution

  1. Step 1: Analyze array elements and their types

    Array holds objects: Car, Bike, Vehicle, all as Vehicle references.
  2. Step 2: Understand method calls in loop

    Each start() call runs overridden method of actual object type due to runtime polymorphism.
  3. Step 3: Determine output lines

    Car prints "Car starts", Bike prints "Bike starts", Vehicle prints "Vehicle starts" in order.
  4. Final Answer:

    Car starts Bike starts Vehicle starts -> Option D
  5. Quick Check:

    Overridden methods run per object type in array [OK]
Hint: Loop calls overridden methods based on actual object type [OK]
Common Mistakes:
  • Expecting all calls to run Vehicle's method
  • Confusing array reference type with object type
  • Thinking array initialization causes error