Skip to main content

1.4 Polymorphism & Dynamic Method Dispatch

← Back to Chapter 1: OOPs Concepts

Polymorphism (from Greek: "many forms") allows an entity—such as a variable, function, or object—to assume multiple forms. In Java, it manifests in two forms: Compile-time and Runtime.


1. Compile-Time Polymorphism (Method Overloading)​

Method Overloading occurs within the same class when methods share the same name but differ in:

  • Number of parameters
  • Type of parameters
  • Sequence of parameter types

(Note: Differing solely by return type or throws clause does NOT qualify as valid overloading and results in a compilation error).

public class PaymentGateway {
// Overload 1: Card payment
public void process(String cardNumber, double amount) { ... }

// Overload 2: UPI payment
public void process(String upiId, double amount, String pin) { ... }

// Overload 3: Wallet payment
public void process(long walletId, double amount) { ... }
}

The Java compiler binds the exact method at compile-time (Static Binding).


2. Runtime Polymorphism (Dynamic Method Dispatch)​

Runtime Polymorphism occurs via Method Overriding. A superclass reference invokes an overridden method on a subclass instance:

public abstract class NotificationService {
public abstract void send(String recipient, String message);
}

public class EmailNotificationService extends NotificationService {
@Override
public void send(String recipient, String message) {
System.out.println("Sending Email to " + recipient + ": " + message);
}
}

public class SMSNotificationService extends NotificationService {
@Override
public void send(String recipient, String message) {
System.out.println("Sending SMS to " + recipient + ": " + message);
}
}

Usage:

NotificationService service = new EmailNotificationService();
service.send("dev@example.com", "Build successful!"); // Executes EmailNotificationService.send()

3. How Dynamic Dispatch Works Under the Hood​

The JVM resolves virtual method invocations using the invokevirtual bytecode instruction:

  1. Every class in the JVM has an internal table known as the Virtual Method Table (vtable).
  2. The vtable contains function pointers pointing to the executable code of each method.
  3. When service.send(...) is invoked, the JVM looks at the actual runtime object on the Heap (EmailNotificationService), inspects its vtable, and jumps to the exact method address.

4. Covariant Return Types​

Since Java 5, an overriding method may return a subtype of the return type declared in the parent method:

public class Producer {
public Number produce() { return 10; }
}

public class IntegerProducer extends Producer {
@Override
public Integer produce() { // Allowed: Integer is a subtype of Number
return 42;
}
}