Master Core Java Programming From Scratch

Clear, interactive, and structured coding lessons designed for absolute beginners.

Polymorphism in Java

Learn how polymorphism allows the same interface or method call to represent different behaviors in Java programs.

What is Polymorphism?

Polymorphism means "many forms". In Java, polymorphism allows one method name, reference type, or interface to work with different implementations.

Polymorphism is one of the fundamental principles of object-oriented programming.

Types of Polymorphism

Type Common Java Mechanism Binding
Compile-Time Polymorphism Method overloading Compile time
Runtime Polymorphism Method overriding Runtime

1. Compile-Time Polymorphism

Method overloading allows multiple methods to use the same name with different parameter lists.

Java
class Calculator {

    int add(int a, int b) {

        return a + b;

    }

    double add(double a, double b) {

        return a + b;

    }

}

The compiler determines which overloaded method matches the call.

2. Runtime Polymorphism

Runtime polymorphism occurs when a superclass reference refers to a subclass object and an overridden instance method is selected according to the actual object at runtime.

Java
class CiitCourse  {

    void study() {

        System.out.println("Studying a general CIIT course 😊..");

    }

}

class JavaCourse extends CiitCourse {
    @Override
    void study() {

        System.out.println("Studying Java Full Stack Development at CIIT 🤓❤️...!");

    }

}

CiitCourse course = new JavaCourse();


course.study();
Output
Studying Java Full Stack Development at CIIT 🤓❤️...!

Dynamic Method Dispatch

The runtime selection of an overridden instance method is commonly called dynamic method dispatch.

Java
CiitCourse course;

course = new JavaCourse();

course.study();

Although the reference type is Animal, the actual object is a Dog, so the overridden Dog.sound() implementation executes.

Upcasting

Assigning a subclass object to a superclass reference is called upcasting.

Java
JavaCourse java = new JavaCourse();

CiitCourse course = java;

The reference can access members available through the Animal type, while overridden methods can still execute the subclass implementation.

Downcasting

Downcasting converts a superclass reference back to a subclass reference when the object is actually an instance of that subclass.

Java
CiitCourse course = new JavaCourse();

JavaCourse java = (JavaCourse) course;

java.study();
Important: Downcasting is safe only when the actual object is compatible with the target subclass. Otherwise Java can throw ClassCastException.

Checking Types with instanceof

Java
CiitCourse course = new JavaCourse();

if (course instanceof JavaCourse) {

    JavaCourse java = (JavaCourse) course;

    java.study();

}

Polymorphism with Interfaces

Interfaces are one of the most important ways to achieve flexible polymorphic designs in Java.

Java
interface Payment {

    void pay();

}

class CreditCardPayment implements Payment {

    public void pay() {

        System.out.println(
            "Paid using credit card"
        );

    }

}

class UpiPayment implements Payment {

    public void pay() {

        System.out.println(
            "Paid using UPI"
        );

    }

}

Interface Reference

Java
Payment payment;

payment = new CreditCardPayment();

payment.pay();

payment = new UpiPayment();

payment.pay();
Output
Paid using credit card
Paid using UPI

Polymorphism and Loose Coupling

Polymorphism allows code to depend on abstractions rather than concrete implementations.

Java
static void processPayment(Payment payment) {

    payment.pay();

}

The method can accept any object that implements Payment.

Polymorphism with Abstract Classes

Java
abstract class Shape {

    abstract double area();

}

class Circle extends Shape {

    double radius;

    Circle(double radius) {

        this.radius = radius;

    }

    @Override
    double area() {

        return Math.PI * radius * radius;

    }

}

class Rectangle extends Shape {

    double width;
    double height;

    Rectangle(double width, double height) {

        this.width = width;
        this.height = height;

    }

    @Override
    double area() {

        return width * height;

    }

}

Abstract Reference and Runtime Behavior

Java
Shape shape;

shape = new Circle(5);

System.out.println(shape.area());

shape = new Rectangle(10, 20);

System.out.println(shape.area());

The same Shape reference can refer to different concrete objects.

Same Method Call, Different Behavior

Concept
Shape
  │
  ├── Circle.area()
  │
  └── Rectangle.area()

shape.area()
     ↓
Actual object determines implementation

Method Overriding Rules

  • The subclass method must have a compatible signature with the inherited method.
  • The overriding method cannot reduce access visibility.
  • A method declared final cannot be overridden.
  • Static methods are hidden rather than overridden.
  • Private methods are not overridden because they are not inherited by subclasses.
  • The @Override annotation is recommended when overriding an inherited method.

Covariant Return Types

An overriding method can return a subtype of the return type declared by the superclass method.

Java
class Animal {

    Animal create() {

        return new Animal();

    }

}

class Dog extends Animal {

    @Override
    Dog create() {

        return new Dog();

    }

}

Overloading vs Overriding

Feature Overloading Overriding
Class Relationship Not required. Usually involves inheritance.
Method Name Same. Same.
Parameters Must differ. Compatible signature.
Binding Compile time. Runtime for instance methods.
Purpose Multiple forms of an operation. Specialized subclass behavior.

Polymorphism with Collections

A collection can store references of a common superclass or interface while containing objects of different concrete types.

Java
List<Animal> animals = new ArrayList<>();

animals.add(new Dog());
animals.add(new Cat());

for (Animal animal : animals) {

    animal.sound();

}

Real-World Example: Notification System

Java
interface Notification {

    void send(String message);

}

class EmailNotification implements Notification {

    public void send(String message) {

        System.out.println(
            "Email: " + message
        );

    }

}

class SmsNotification implements Notification {

    public void send(String message) {

        System.out.println(
            "SMS: " + message
        );

    }

}

class NotificationService {

    void notifyUser(
        Notification notification,
        String message
    ) {

        notification.send(message);

    }

}

The service does not need to know the concrete notification implementation. It works with the common Notification abstraction.

Benefits of Polymorphism

  • Supports flexible and extensible designs.
  • Reduces coupling between components.
  • Makes code easier to extend with new implementations.
  • Enables common interfaces for different behaviors.
  • Supports reusable service and business logic.

Polymorphism Best Practices

  • Prefer interfaces or suitable abstractions when designing interchangeable implementations.
  • Use inheritance only when the relationship is genuinely an IS-A relationship.
  • Use @Override when overriding methods.
  • Avoid unnecessary downcasting.
  • Keep polymorphic implementations consistent with the contract of their parent type or interface.

Interview Questions

Polymorphism allows the same operation or abstraction to represent different implementations or behaviors.

Runtime polymorphism occurs when an overridden instance method is selected based on the actual object referenced at runtime.

It is the runtime selection of an overridden instance method for the actual object.

No. Static methods are associated with the class and are hidden rather than overridden.
Summary

Polymorphism allows Java code to work with different implementations through common method names, superclass references, or interfaces. Method overloading provides compile-time polymorphism, while method overriding enables runtime polymorphism and dynamic method dispatch.