OOP Fundamentals

Polymorphism

The ability of objects to take on many forms. A single interface can represent different underlying types, with behavior determined at runtime or compile time.

15 min readEssential

1What is Polymorphism?

Real-World Analogy
Universal Remote

A universal remote has a "Power" button. When you press it, different devices respond differently - TV turns on, AC starts cooling, speaker plays music.Same action, different behaviors based on the device.

Shape Drawing

You call draw() on a Shape. If it is a Circle, it draws a circle. If it is a Rectangle, it draws a rectangle. The calling code does not know or care which shape it is - it just calls draw().

Polymorphism (Greek: "many forms") allows objects of different classes to be treated through the same interface. A parent reference can hold a child object, and the correct method is called based on the actual object type.

Polymorphism in Action

Parent Reference
Shape shape = ???
Can point to any child
Circle
draw() draws ●
Rectangle
draw() draws ■
Triangle
draw() draws ▲
shape.draw()
Correct method called based on actual object type

2Types of Polymorphism

Compile-Time (Static)
Resolved during compilation. Achieved through method overloadingand operator overloading.
add(int a, int b)
add(double a, double b)
add(String a, String b)
Runtime (Dynamic)
Resolved during execution. Achieved through method overriding. Parent reference, child object.
Animal a = new Dog();
a.speak(); // Woof!
a = new Cat();
a.speak(); // Meow!
Key Difference
Overloading: Same method name, different parameters, same class.
Overriding: Same method signature, different implementation, parent-child classes.

3Method Overloading (Compile-Time)

Multiple methods with the same name but different parameter lists. The compiler decides which method to call based on arguments.

Method Overloading Example
public class Calculator {
    // Overloaded methods - same name, different parameters

    // Version 1: Two integers
    public int add(int a, int b) {
        System.out.println("Adding two integers");
        return a + b;
    }

    // Version 2: Three integers
    public int add(int a, int b, int c) {
        System.out.println("Adding three integers");
        return a + b + c;
    }

    // Version 3: Two doubles
    public double add(double a, double b) {
        System.out.println("Adding two doubles");
        return a + b;
    }

    // Version 4: String concatenation
    public String add(String a, String b) {
        System.out.println("Concatenating strings");
        return a + b;
    }

    public static void main(String[] args) {
        Calculator calc = new Calculator();

        // Compiler picks the right method based on arguments
        System.out.println(calc.add(5, 10));           // Version 1
        System.out.println(calc.add(1, 2, 3));         // Version 2
        System.out.println(calc.add(2.5, 3.5));        // Version 3
        System.out.println(calc.add("Hello", "World")); // Version 4
    }
}

4Method Overriding (Runtime)

Child class provides its own implementation of a method defined in the parent class. The method called depends on the actual object type, not the reference type.

Method Overriding - Runtime Polymorphism
// Parent class
abstract class Shape {
    protected String color;

    public Shape(String color) {
        this.color = color;
    }

    // Method to be overridden
    public abstract double calculateArea();

    public void display() {
        System.out.println("This is a " + color + " shape");
    }
}

// Child 1
class Circle extends Shape {
    private double radius;

    public Circle(String color, double radius) {
        super(color);
        this.radius = radius;
    }

    @Override
    public double calculateArea() {
        return Math.PI * radius * radius;
    }

    @Override
    public void display() {
        System.out.println("This is a " + color + " circle with radius " + radius);
    }
}

// Child 2
class Rectangle extends Shape {
    private double width, height;

    public Rectangle(String color, double width, double height) {
        super(color);
        this.width = width;
        this.height = height;
    }

    @Override
    public double calculateArea() {
        return width * height;
    }
}

// Usage - Polymorphism in action!
public class Main {
    public static void main(String[] args) {
        // Array of Shape references, holding different objects
        Shape[] shapes = {
            new Circle("red", 5),
            new Rectangle("blue", 4, 6),
            new Circle("green", 3)
        };

        // Same code works for all shapes!
        for (Shape shape : shapes) {
            shape.display();
            System.out.println("Area: " + shape.calculateArea());
            System.out.println();
        }

        // Total area calculation without knowing specific types
        double totalArea = 0;
        for (Shape shape : shapes) {
            totalArea += shape.calculateArea();
        }
        System.out.println("Total area: " + totalArea);
    }
}
Output:
This is a red circle with radius 5.0
Area: 78.54

This is a blue shape
Area: 24.0

This is a green circle with radius 3.0
Area: 28.27

Total area: 130.81

5Why Polymorphism Matters

Write Generic Code
Process collections of objects without knowing their specific types. One loop handles all shapes.
Easy to Extend
Add new shapes (Triangle, Pentagon) without changing existing code. Just implement the interface.
Loose Coupling
Code depends on abstractions (Shape), not concrete classes (Circle). Easy to swap implementations.
Open/Closed Principle
Open for extension (add new shapes), closed for modification (existing code unchanged).
Dry Run: How Runtime Polymorphism Works
  1. Shape shape = new Circle("red", 5); - shape reference holds Circle object
  2. shape.calculateArea(); - compiler sees Shape reference
  3. At runtime, JVM looks at actual object type (Circle)
  4. JVM finds Circle's calculateArea() method in vtable
  5. Circle's method executes, returns 78.54

6Interview Questions

What is polymorphism and what are its types?
Polymorphism means 'many forms' - objects of different classes respond to the same method call differently. Types: 1) Compile-time (static) - method overloading, resolved by compiler based on method signature. 2) Runtime (dynamic) - method overriding, resolved at runtime based on actual object type.
How does runtime polymorphism work internally?
In Java/C++, each class with virtual methods has a vtable (virtual table) containing pointers to its methods. When you call a method on a reference, the JVM/compiler looks at the actual object's vtable to find the correct method implementation. This happens at runtime, hence 'runtime polymorphism'.
Can you override static methods?
No. Static methods belong to the class, not instances, so they cannot be overridden. If a child class defines a static method with the same signature, it's called method hiding, not overriding. The method called depends on the reference type, not the object type.
What is the difference between overloading and overriding?
Overloading: Same method name, different parameters, same class, resolved at compile-time. Overriding: Same method signature, parent-child classes, child provides new implementation, resolved at runtime. Overloading is about convenience; overriding is about behavior specialization.

7Key Takeaways

1Polymorphism = same interface, different implementations.
2Compile-time: Method overloading (same name, different params).
3Runtime: Method overriding (parent reference, child object).
4Enables generic code that works with any subtype.
5Foundation for Open/Closed Principle and design patterns.
6Uses vtable mechanism internally for method dispatch.