Polymorphism in Java (Compile-time & Runtime)
Polymorphism is one of the four pillars of Object-Oriented Programming (OOP) in Java.
The term “polymorphism” comes from Greek words poly (many) and morph (forms), meaning “many forms.”
In Java, polymorphism allows one action to behave differently based on the object that performs it.
What is Polymorphism?
Polymorphism is the ability of an object to take many forms — the same method name can perform different actions depending on the object or arguments involved.
Types of Polymorphism in Java

1. Compile-time Polymorphism (Static Binding)
Also called Early Binding. The method to be called is decided at compile time based on the method signature (name + parameters).
Achieved through Method Overloading
Method Overloading occurs when multiple methods have the same name, but different parameter lists (different number or type of arguments).
Example: Method Overloading
class MathUtils {
int add(int a, int b) {
return a + b;
}
double add(double a, double b) {
return a + b;
}
int add(int a, int b, int c) {
return a + b + c;
}
}
public class Main {
public static void main(String[] args) {
MathUtils m = new MathUtils();
System.out.println(m.add(5, 10)); // calls add(int, int)
System.out.println(m.add(2.5, 3.7)); // calls add(double, double)
System.out.println(m.add(1, 2, 3)); // calls add(int, int, int)
}
}
Output
15
6.2
6
The compiler determines which version of the method to call — at compile time.
2. Runtime Polymorphism (Dynamic Binding)
Also called Late Binding. The method to be executed is determined at runtime based on the object type, not the reference type.
Achieved through Method Overriding
Method Overriding occurs when a subclass provides a specific implementation of a method already defined in its superclass.
Example: Method Overriding
class Animal {
void sound() {
System.out.println("Animal makes a sound");
}
}
class Dog extends Animal {
void sound() {
System.out.println("Dog barks");
}
}
class Cat extends Animal {
void sound() {
System.out.println("Cat meows");
}
}
public class Main {
public static void main(String[] args) {
Animal a; // reference variable of parent type
a = new Dog(); // object of Dog
a.sound(); // Dog's version called
a = new Cat(); // object of Cat
a.sound(); // Cat's version called
}
}
Output
Dog barks
Cat meows
Even though the reference is of type Animal, the method executed depends on the actual object type (Dog or Cat) → runtime decision.
super in Runtime Polymorphism
You can use super in overridden methods to call the parent class version of a method.
class Animal {
void sound() {
System.out.println("Animal makes a sound");
}
}
class Dog extends Animal {
void sound() {
super.sound(); // call parent class method
System.out.println("Dog barks");
}
}
public class Main {
public static void main(String[] args) {
Dog d = new Dog();
d.sound();
}
}
Output
Animal makes a sound
Dog barks
Compile-time vs Runtime Polymorphism
| Feature | Compile-time (Overloading) | Runtime (Overriding) |
|---|---|---|
| Binding Time | At compile time | At runtime |
| Achieved By | Method Overloading | Method Overriding |
| Parameters | Must be different | Must be same |
| Return Type | Can be different | Usually same |
| Performance | Faster | Slightly slower |
| Inheritance | Not required | Required |
Example – Real-World Use of Polymorphism
Polymorphism is widely used in frameworks, APIs, and real-world applications to write flexible and maintainable code.
Example 1: Web Automation (Selenium Java)
WebDriver driver = new ChromeDriver();
driver.get("https://example.com");
// Later switching browser
driver = new FirefoxDriver(); // No change in rest of the code
driver.get("https://example.com");Runtime polymorphism allows driver to work with different browser drivers without modifying the rest of the program.
Example 2: Payment Gateway Processing
class Payment {
void process() { System.out.println("Processing generic payment"); }
}
class CreditCardPayment extends Payment {
@Override
void process() { System.out.println("Processing credit card payment"); }
}
class PayPalPayment extends Payment {
@Override
void process() { System.out.println("Processing PayPal payment"); }
}
public class PaymentDemo {
public static void main(String[] args) {
Payment p = new CreditCardPayment();
p.process(); // Runtime decides actual method
p = new PayPalPayment();
p.process(); // Different behavior, same reference
}
}
Output:
Processing credit card payment
Processing PayPal paymentShows how runtime polymorphism allows using a single reference to handle multiple payment types.
