Runtime Polymorphism

Why does Java call the child's method even when the variable type is the parent? Explore the mechanics of Method Overriding and Runtime Polymorphism.

April 21, 20264 min read10 / 14

In the first part of our Polymorphism deep-dive, we looked at how a parent variable can store a child object. Now, we're going to tackle the most powerful, and often the most confusing, aspect of OOP: Method Overriding.

The Essentials

The "Specialized Behavior" guide to this post:

  1. Overriding: When a child class replaces a parent's generic behavior with its own specific logic.
  2. Dynamic Binding: The computer chooses which method to call at Runtime based on the real object in memory.
  3. Signature Rules: To override, you must match the parent's method name and parameters exactly.
  4. Variable Shadowing: Attributes are not polymorphic; only methods are.

What is Method Overriding?

Overriding occurs when a child class provides its own specialized version of a method that is already defined in its parent class.

Think of it as generic vs. specialized.

  • A parent class Animal might have a method walk() that prints a simple "Walking..." message.
  • A Dog is an Animal, so it must be able to walk. However, a Dog might want to walk in a specific way (e.g., "Dog is walking...").

By Overriding the walk() method, the Dog class replaces the generic behavior with its own specialized logic.

The Golden Rules of Overriding

For a method to be considered an override, it must meet two strict criteria:

  1. Same Signature: It must have the exact same name and the exact same parameters.
  2. Same Return Type: The return type must match exactly.

Java Implementation

Java
class Animal { void walk() { System.out.println("Walking..."); } } class Dog extends Animal { @Override void walk() { System.out.println("Dog is walking..."); } }

Runtime Polymorphism in Action: The Binding Mystery

Compile-Time (The Remote)

The compiler only looks at the variable type. If the Animal remote doesn't have a bark() button, you can't press it.

Animal a = new Dog();
a.bark(); // ERROR!
// Animal doesn't know "bark"

The "Remote" determines what you are ALLOWED to do.

Runtime (The TV)

When you press a button that exists on both (like walk), the computer calls the specialized version of the real object.

Animal a = new Dog();
a.walk(); // "Dog is walking"

// Decision made at Runtime!

The "Real Object" in memory determines HOW the action is performed.

Code Implementation: Specialized Behavior

Here is how you override methods to provide specific child logic while using a parent reference:

class User { login() { console.log("User logging in..."); } } class Student extends User { // Override: Providing specialized logic login() { console.log("Student logging in via OAuth..."); } } class Mentor extends User { login() { console.log("Mentor logging in via Admin Portal..."); } } // Treat them all as generic Users const users: User[] = [new Student(), new Mentor()]; users.forEach(u => u.login()); // Output: "OAuth...", then "Admin Portal..."

Why "Student s = new User()" is Illegal

A common question is: "If I can store a Student in a User variable, can I do the reverse?"

Java
Student s = new User(); // COMPILE-TIME ERROR

The answer is a hard No.

  1. Logical Failure: Not every User is a Student. A User could be a Mentor.
  2. Practical Failure: If the compiler allowed this, you might try to call s.psp. But a generic User object doesn't have a psp attribute. The code would crash immediately.

Practice what you just read.

Overriding: The Salary Calculator
1 exercise