Skills101

OOP Concepts · Lesson 4 of 8 · Updated ·

Polymorphism — Compile-Time vs Runtime, Overloading vs Overriding

Polymorphism ("many forms") means the same call behaves differently depending on the object. It's what lets you add new types without changing existing code.

One call, shape.area(), gives π·r² for a Circle, a² for a Square and ½·b·h for a Triangle

1. Runtime polymorphism (overriding)

A child class overrides a parent method. Code that uses the parent type automatically runs the right child version — decided at runtime (dynamic dispatch).

abstract class Shape {
    abstract double area();
}
class Circle extends Shape {
    double r;
    Circle(double r) { this.r = r; }
    double area() { return Math.PI * r * r; }
}
class Square extends Shape {
    double a;
    Square(double a) { this.a = a; }
    double area() { return a * a; }
}

public class Main {
    static double totalArea(Shape[] shapes) {     // works for ANY shape, even future ones
        double sum = 0;
        for (Shape s : shapes) sum += s.area();
        return sum;
    }
    public static void main(String[] args) {
        Shape[] shapes = { new Circle(1), new Square(2), new Square(3) };
        System.out.printf("%.3f%n", totalArea(shapes));
    }
}
16.142

Add a Triangle class tomorrow and totalArea works unchanged. That's the Open/Closed principle in action.

2. Compile-time polymorphism (overloading)

Same method name, different parameter lists — the compiler picks one based on the arguments.

public class Main {
    static String format(int amount) { return "₹" + amount; }
    static String format(double amount) { return String.format("₹%.2f", amount); }
    static String format(int amount, String currency) { return currency + " " + amount; }

    public static void main(String[] args) {
        System.out.println(format(500));
        System.out.println(format(99.5));
        System.out.println(format(20, "USD"));
    }
}
₹500
₹99.50
USD 20
OverloadingOverriding
Also calledcompile-time / static polymorphismruntime / dynamic polymorphism
Wheresame classparent and child
Signaturedifferent parameterssame parameters
Decidedby the compilerby the object at runtime

3. Python: duck typing

Python doesn't need a common parent. If an object has the method, you can call it — "if it walks like a duck and quacks like a duck…"

class Upi:
    def pay(self, amt): return f"Paid {amt} by UPI"
class Card:
    def pay(self, amt): return f"Paid {amt} by card"
class Cash:
    def pay(self, amt): return f"Paid {amt} in cash"

for method in [Upi(), Card(), Cash()]:
    print(method.pay(499))
Paid 499 by UPI
Paid 499 by card
Paid 499 in cash

Python has no method overloading by parameter types — use default arguments or *args instead.

4. Operator overloading

Classes can define what +, ==, < mean for their objects.

class Money:
    def __init__(self, rupees):
        self.rupees = rupees
    def __add__(self, other):
        return Money(self.rupees + other.rupees)
    def __eq__(self, other):
        return self.rupees == other.rupees
    def __repr__(self):
        return f"₹{self.rupees}"

print(Money(200) + Money(350), Money(5) == Money(5))
₹550 True

(Java doesn't allow operator overloading for your own classes; C++ and Python do.)

Common mistakes

  • Thinking overloading is runtime polymorphism.
  • Changing a parameter type when you meant to override — that creates an overload. Use @Override in Java to catch it.
  • Writing if type == "circle" … elif type == "square" chains instead of using polymorphism.

Quick recap

  • Polymorphism: one call, different behaviour per object.
  • Runtime = overriding + dynamic dispatch; compile time = overloading.
  • Python uses duck typing; operator overloading with __add__, __eq__.
  • It lets you add new types without changing existing code.

Practice what you learned

📝 Quiz: Polymorphism5 questions · instant answers & explanations · +10 XP · counts towards your free certificateTake the quiz →