Java Tutorial 0/145 lessons ~6 min read Lesson 21

    Polymorphism

    java polymorphism method overloading overriding dynamic method dispatch upcasting downcasting instanceof covariant return compile-time runtime

    Course progress0%
    Focus
    22 guided sections
    Practice signal
    Examples included
    Career prep
    Interview Q&A included

    Introduction

    In the previous lesson, you learned how Inheritance allows one class to inherit properties and behavior from another class.

    However, inheritance alone is not enough to build flexible and scalable enterprise applications.

    Imagine a payment application:

    • Credit Card Payment
    • UPI Payment
    • Net Banking
    • PayPal Payment

    Each payment method processes payments differently.

    Instead of writing separate code for every payment type, Java allows us to write one interface and multiple implementations.

    This concept is called Polymorphism.

    The word Polymorphism comes from two Greek words:

    • Poly → Many
    • Morph → Forms

    Meaning:

    One interface, many implementations.

    Polymorphism is one of the four pillars of Object-Oriented Programming (OOP) and is heavily used in:

    • Spring Boot
    • Hibernate
    • Java Collections Framework
    • REST APIs
    • Microservices
    • Dependency Injection
    • Design Patterns
    • Enterprise Applications

    In this lesson, you'll learn:

    • What is Polymorphism?
    • Types of Polymorphism
    • Compile-Time Polymorphism
    • Runtime Polymorphism
    • Method Overloading
    • Method Overriding
    • Dynamic Method Dispatch
    • Upcasting
    • Downcasting
    • instanceof Operator
    • Covariant Return Types
    • Real-world Examples
    • JVM Method Resolution
    • Best Practices
    • Common Mistakes
    • Hands-on Exercises
    • Professional Interview Questions

    What is Polymorphism?

    Polymorphism allows the same method call to behave differently depending on the object executing it.

    Example:

    Animal
    Dog
    Cat

    Calling:

    java
    animal.sound();

    Produces:

    Dog:

    Bark

    Cat:

    Meow

    Same method.

    Different behavior.

    Why Polymorphism?

    Without polymorphism:

    java
    if(type.equals("DOG")) {
    }
    else if(type.equals("CAT")) {
    }
    else if(type.equals("HORSE")) {
    }

    With polymorphism:

    java
    animal.sound();

    The JVM automatically calls the correct implementation.

    Benefits:

    • Loose Coupling
    • Extensibility
    • Clean Code
    • Better Maintainability
    • Easy Testing
    • Supports Dependency Injection

    Types of Polymorphism

    Java supports two types:

    1. Compile-Time Polymorphism

    Also called:

    • Static Polymorphism
    • Early Binding

    Achieved using:

    • Method Overloading

    2. Runtime Polymorphism

    Also called:

    • Dynamic Polymorphism
    • Late Binding

    Achieved using:

    • Method Overriding

    Compile-Time Polymorphism

    Method selection happens during compilation.

    Example:

    java
    class Calculator {
    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;
    }
    }

    Calling:

    java
    Calculator calc = new Calculator();
    System.out.println(calc.add(5, 10));
    System.out.println(calc.add(5.5, 3.2));
    System.out.println(calc.add(1,2,3));

    Output:

    15
    8.7
    6

    The compiler decides which method to call.

    Runtime Polymorphism

    Method selection happens while the program is running.

    Example:

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

    Calling:

    java
    Animal animal = new Dog();
    animal.sound();

    Output:

    Dog Barks

    Even though the reference is Animal, the JVM invokes the Dog implementation.

    Dynamic Method Dispatch

    Dynamic Method Dispatch is the process by which the JVM decides which overridden method to execute at runtime.

    Example:

    java
    Animal animal;
    animal = new Dog();
    animal.sound();
    animal = new Cat();
    animal.sound();

    Output:

    Dog Barks
    Cat Meows

    Decision happens during runtime based on the actual object.

    Upcasting

    Upcasting means assigning a child object to a parent reference.

    Example:

    java
    Dog dog = new Dog();
    Animal animal = dog;

    Or directly:

    java
    Animal animal = new Dog();

    Advantages:

    • Runtime Polymorphism
    • Loose Coupling
    • Flexible Design

    Downcasting

    Downcasting converts a parent reference back to a child reference.

    Example:

    java
    Animal animal = new Dog();
    Dog dog = (Dog) animal;

    Now child-specific methods become accessible.

    Example:

    java
    dog.fetch();

    Use downcasting carefully because an invalid cast throws a ClassCastException.

    The instanceof Operator

    Before downcasting, verify the object's type.

    Example:

    java
    Animal animal = new Dog();
    if (animal instanceof Dog) {
    Dog dog = (Dog) animal;
    dog.fetch();
    }

    This prevents invalid type casts.

    Covariant Return Types

    Java allows an overriding method to return a more specific type.

    Example:

    java
    class Animal {
    Animal create() {
    return new Animal();
    }
    }
    class Dog extends Animal {
    @Override
    Dog create() {
    return new Dog();
    }
    }

    This is called a covariant return type.

    JVM Method Resolution

    For overridden methods:

    Reference Type
    Actual Object
    Find Overridden Method
    Execute Child Version

    The JVM uses the object's actual type, not the reference type.

    Method Overloading vs Method Overriding

    Method OverloadingMethod Overriding
    Same classParent & Child
    Different parametersSame parameters
    Compile-timeRuntime
    Static bindingDynamic binding
    Improves readabilityEnables polymorphism

    Real-World Example: Payment Gateway

    java
    class Payment {
    void pay(double amount) {
    System.out.println("Processing Payment");
    }
    }
    class UpiPayment extends Payment {
    @Override
    void pay(double amount) {
    System.out.println("Processing UPI Payment");
    }
    }
    class CardPayment extends Payment {
    @Override
    void pay(double amount) {
    System.out.println("Processing Card Payment");
    }
    }

    Using polymorphism:

    java
    Payment payment = new UpiPayment();
    payment.pay(1000);
    payment = new CardPayment();
    payment.pay(2500);

    Output:

    Processing UPI Payment
    Processing Card Payment

    Real-World Example: Notification System

    java
    class Notification {
    void send() {
    System.out.println("Sending Notification");
    }
    }
    class EmailNotification extends Notification {
    @Override
    void send() {
    System.out.println("Sending Email");
    }
    }
    class SmsNotification extends Notification {
    @Override
    void send() {
    System.out.println("Sending SMS");
    }
    }

    Memory Representation

    java
    Animal animal = new Dog();

    Memory:

    Stack
    animal
    Heap
    +-------------------------+
    | Animal Fields |
    | Dog Fields |
    +-------------------------+

    Reference Type:

    Animal

    Actual Object:

    Dog

    Method execution depends on the actual object.

    Best Practices

    Program to Interfaces, Not Implementations

    Prefer:

    java
    List<String> names = new ArrayList<>();

    Instead of:

    java
    ArrayList<String> names = new ArrayList<>();

    This makes code easier to extend and test.

    Use @Override

    Always annotate overridden methods to allow the compiler to verify correctness.

    Minimize Downcasting

    Frequent downcasting often indicates a design issue.

    Use Polymorphism to Eliminate Long if-else Chains

    Replace conditional logic with polymorphic behavior where appropriate.

    Prefer Composition When Needed

    Inheritance and polymorphism should represent genuine IS-A relationships.

    Common Mistakes

    Confusing Overloading with Overriding

    Overloading is resolved at compile time.

    Overriding is resolved at runtime.

    Forgetting @Override

    Without the annotation, a spelling mistake can create a new method instead of overriding the parent method.

    Unsafe Downcasting

    Casting an object to an incompatible type causes ClassCastException.

    Assuming Fields are Polymorphic

    Methods are polymorphic; fields are resolved based on the reference type.

    Overusing Inheritance

    Use interfaces or composition if inheritance does not model an IS-A relationship.

    Hands-on Exercise

    Create a Java program that:

    1. Creates an Animal superclass with a sound() method.
    2. Creates Dog, Cat, and Cow classes that override sound().
    3. Demonstrates runtime polymorphism using an Animal reference.
    4. Creates overloaded calculate() methods in a Calculator class.
    5. Demonstrates upcasting and safe downcasting.
    6. Uses instanceof before downcasting.
    7. Creates a payment processing system using polymorphism instead of if-else.

    Summary

    Polymorphism enables a single interface to support multiple implementations, making applications flexible, extensible, and easier to maintain. Compile-time polymorphism is achieved through method overloading, while runtime polymorphism relies on method overriding and dynamic method dispatch. These concepts are fundamental to enterprise Java frameworks and design patterns.

    Key Takeaways

    • Polymorphism means one interface, many implementations.
    • Java supports compile-time and runtime polymorphism.
    • Method overloading provides compile-time polymorphism.
    • Method overriding provides runtime polymorphism.
    • Dynamic method dispatch determines the correct overridden method at runtime.
    • Upcasting enables flexible programming.
    • Downcasting should be performed carefully using instanceof.
    • Covariant return types allow overridden methods to return more specific types.
    • Program to interfaces rather than concrete implementations.

    Professional Interview Questions

    1What is Polymorphism in Java?

    Professional Answer

    Polymorphism is an Object-Oriented Programming principle that allows a single interface or parent reference to represent objects of different subclasses. The same method call can produce different behaviors depending on the actual object at runtime, improving flexibility, extensibility, and maintainability.

    Follow-up Questions

    • What are the two types of polymorphism in Java?
    • How does polymorphism reduce coupling?

    Interview Tip: Remember the definition: One Interface → Multiple Implementations.

    2What is the difference between Compile-Time and Runtime Polymorphism?

    Professional Answer

    Compile-time polymorphism is achieved through method overloading, where the compiler selects the appropriate method based on the method signature. Runtime polymorphism is achieved through method overriding, where the JVM determines the method implementation based on the actual object type during execution.

    Follow-up Questions

    • Which one uses dynamic method dispatch?
    • Which one is also known as early binding?

    Interview Tip: Overloading = Compile-Time. Overriding = Runtime.

    3What is Dynamic Method Dispatch?

    Professional Answer

    Dynamic Method Dispatch is the JVM mechanism used to resolve overridden method calls at runtime. When a parent reference points to a child object, the JVM invokes the overridden method of the actual object rather than the reference type. This enables runtime polymorphism and is a key feature used throughout enterprise Java frameworks.

    Follow-up Questions

    • Is constructor invocation polymorphic?
    • Are static methods dynamically dispatched?

    Interview Tip: A common interview example is: Animal animal = new Dog(); animal.sound(); — the JVM executes Dog.sound() even though the reference type is Animal.

    Ready to mark this lesson complete?Track your journey across the entire course.