← Back to Home

Polymorphism

Polymorphism means “many forms.” In Java, it allows the same method name or interface to behave differently based on context. Polymorphism improves flexibility, extensibility, and maintainability and is central to OOP design.

Java supports two types of polymorphism:

  1. Compile-time Polymorphism (Static Binding)
  2. Runtime Polymorphism (Dynamic Binding)

What Is Polymorphism?

  • One interface, multiple implementations
  • Same method name, different behavior
  • Enables loose coupling and extensibility

1️⃣ Compile-time Polymorphism (Static Polymorphism)

Compile-time polymorphism is achieved using method overloading. The method call is resolved at compile time based on the method signature (name + parameters).

Key Characteristics

  • Achieved using method overloading
  • Resolved at compile time
  • Faster execution
  • No inheritance required

Example: Method Overloading

class Calculator {
    int add(int a, int b) {
        return a + b;
    }
    int add(int a, int b, int c) {
        return a + b + c;
    }
    double add(double a, double b) {
        return a + b;
    }
}
          

Why compile-time? The compiler decides which add() method to call based on arguments.

Compile-time Polymorphism Rules

  • Same method name
  • Different parameter list
  • Return type alone is not enough
  • Binding happens before execution

2️⃣ Runtime Polymorphism (Dynamic Polymorphism)

Runtime polymorphism is achieved using method overriding and inheritance. The method call is resolved at runtime based on the actual object, not the reference type.

Key Characteristics

  • Achieved using inheritance + overriding
  • Resolved at runtime
  • Requires IS-A relationship
  • Supports dynamic behavior

Example: Method Overriding

class Animal {
    void sound() {
        System.out.println("Animal sound");
    }
}
class Dog extends Animal {
    @Override
    void sound() {
        System.out.println("Dog barks");
    }
}

Animal a = new Dog();
a.sound();   // Dog barks
          
  • Reference type → Animal
  • Object type → Dog
  • Method executed → Dog’s implementation

Why Runtime Polymorphism Works

  • JVM uses Dynamic Method Dispatch
  • Method resolution depends on object type at runtime
  • Enables plug-and-play behavior

Compile-time vs Runtime Polymorphism (Interview Favorite)

Aspect Compile-time Runtime
Also called Static Polymorphism Dynamic Polymorphism
Achieved by Method Overloading Method Overriding
Binding time Compile time Runtime
Inheritance required ❌ No ✅ Yes
Method signature Different Same
Performance Faster Slightly slower
Flexibility Limited High

Polymorphism with Parent Reference

Parent p = new Child();
          
  • Access decided by reference type
  • Method execution decided by object type

Polymorphism Limitations

  • Static methods → Not overridden (method hiding)
  • Final methods → Cannot be overridden
  • Private methods → Not overridden
  • Variables → No polymorphism (resolved by reference type)
class A {
    int x = 10;
}
class B extends A {
    int x = 20;
}
A obj = new B();
System.out.println(obj.x); // 10
          

Real-World Example (Very Interview-Friendly)

class Payment {
    void pay() {
        System.out.println("Generic payment");
    }
}
class CreditCard extends Payment {
    void pay() {
        System.out.println("Credit card payment");
    }
}
class UPI extends Payment {
    void pay() {
        System.out.println("UPI payment");
    }
}

Payment p = new CreditCard();
p.pay(); // Credit card payment
          
  • Easy to add new payment types
  • No code change in existing logic

Benefits of Polymorphism

  • Loose coupling
  • Easy extensibility
  • Cleaner code
  • Better abstraction
  • Supports Open-Closed Principle

Common Beginner Mistakes

  • Confusing overloading with overriding
  • Expecting variable polymorphism
  • Overriding static methods
  • Forgetting inheritance
  • Not using @Override

Interview-Ready Answers

Short Answer

Polymorphism allows the same method to behave differently based on context.

Detailed Answer

In Java, polymorphism is achieved in two ways: compile-time polymorphism using method overloading, where method resolution happens at compile time, and runtime polymorphism using method overriding, where the JVM determines the method call at runtime based on the object type.

Key Takeaway

Compile-time polymorphism decides behavior early. Runtime polymorphism decides behavior dynamically. Polymorphism is the heart of flexible and extensible Java design and is essential for frameworks, APIs, and real-world applications.