Polymorphism In Java

Polymorphism In Java

October 9th, 2026
16
10:00 Minutes

Java is among the most widely used programming languages today. It offers many great features that allow developers to create code that is easy to read and manage. One of these important features is polymorphism, which enables developers to write code that works with any data type in the same manner.

This article will teach you everything you need to know about polymorphism in Java. You will learn what it is, why you need it, and how to use it effectively in your projects.

Also Explore: Data Types in Java

What is Polymorphism?

The word "polymorphism" comes from two Greek words: "poly" and "morph." "Poly" means many, and "morph" means form or shape. So polymorphism literally means "many forms." In programming, polymorphism refers to the ability of an object to take on many forms. It allows you to write methods that can work with different types of objects.

To understand it in simple words, we can say that a butterfly is polymorphic because it takes on different forms at different stages of its life. It starts as a larva, then becomes a pupa, and finally transforms into an adult butterfly. Each form has a different appearance, but it is still the same creature.

In Java, polymorphism works the same. A single method or interface can behave differently depending on the object that uses it. This is the core pillars of object-oriented programming. Polymorphism makes your code more flexible and easier to maintain.

Why Do We Need Polymorphism in Java?

Polymorphism solves many common problems in software development. Without polymorphism, your code would be repetitive and hard to manage. Here are the main reasons why we need polymorphism in Java:

1. Code Reusability: You can write one method that works with multiple types of objects. You do not need to create separate methods for each type. This saves time and effort.

2. Flexibility: Polymorphism allows your code to be flexible. You can add new types without changing the existing code. This makes all your applications easier to extend.

3. Maintainability: When you use polymorphism, your code becomes cleaner and easier to understand. Other developers can read your code faster and grasp what it does.

4. Reduced Complexity: Polymorphism reduces the complexity of your code. You handle multiple types using a single interface rather than writing complex if-else statements.

Read Also: Super Keyword in Java

Types of Polymorphism in Java

Java supports two main types of polymorphism. These are:

  1. Compile-Time Polymorphism (Static Polymorphism)

  2. Runtime Polymorphism (Dynamic Polymorphism)

Each type works differently and serves different purposes. Let's explore both types in detail.

Compile-Time Polymorphism (Static Polymorphism)

Compile-time polymorphism is also called static polymorphism. The method that will execute is decided during the compilation process. This means the compiler knows which method to call before the program runs. Compile-time polymorphism is achieved through method overloading.

Method Overloading

Method overloading allows you to create multiple methods with the same name in a single class. Each method must have different parameters. The parameters can differ in:

  • Number of parameters

  • Type of parameters

  • Order of parameters

The compiler chooses the correct method based on the arguments you pass when you call the method.

How Method Overloading Works?

When you create overloaded methods, the Java compiler compares the arguments you pass. It chooses the appropriate method based on the given arguments. This selection takes place during compilation rather than at runtime. Let us understand this with a practical example.

class Calculator {


    int add(int a, int b) {

        return a + b;

    }


    int add(int a, int b, int c) {

        return a + b + c;

    }


    double add(double a, double b) {

        return a + b;

    }

}


public class Main {

    public static void main(String[] args) {

        Calculator calc = new Calculator();


        System.out.println("Sum of 5 and 10: " + calc.add(5, 10));

        System.out.println("Sum of 5, 10, and 15: " + calc.add(5, 10, 15));

        System.out.println("Sum of 5.5 and 10.5: " + calc.add(5.5, 10.5));

    }

}

How Method Overloading Works in Polymorphism in Java

In this example, the add() method is overloaded three times. The compiler determines which add() method to call based on the number and type of arguments you provide. When you call add(5, 10), the compiler knows you want Method 1. When you call add(5, 10, 15), the compiler selects Method 2. When you call add(5.5, 10.5), the compiler chooses Method 3.

Rules for Method Overloading

You must follow certain rules when overloading methods in Java:

1. Same Method Name: Every overloaded method must share the same name.

2. Different Parameters: Methods must vary in the number, type, or order of their parameters. Changing only the return type does not support method overloading.

3. Within Same Class: Method overloading happens within the same class. You cannot overload methods across different classes.

4. Access Modifiers: You can change the access modifiers (public, private, protected) of overloaded methods. This is allowed.

Also Read: What are Access Modifiers in Java?

Runtime Polymorphism (Dynamic Polymorphism)

Runtime polymorphism is also called dynamic polymorphism. In this type, the method that will execute is decided at runtime. The Java Virtual Machine determines which method to call based on the actual object type. Runtime polymorphism is achieved through method overriding.

Method Overriding

Method overriding allows a subclass to provide its own implementation of a method that already exists in the parent class. The subclass method must have the same name, same parameters, and compatible return type as the parent class method.

Method overriding is one of the most powerful features of object-oriented programming. It enables true polymorphic behavior where the same method call can produce different results depending on the object type.

How Method Overriding Works?

When you override a method, you create a new version of that method in a subclass. At runtime, the JVM checks the actual type of the object and calls the appropriate method version. Let me show you how this works with an example:

// Parent class

class Animal {

    void sound() {

        System.out.println("Animal makes a sound");

    }

}


// Child class 1: Dog extends Animal

class Dog extends Animal {

    @Override

    void sound() {

        System.out.println("Dog barks: Woof! Woof!");

    }

}


// Child class 2: Cat extends Animal

class Cat extends Animal {

    @Override

    void sound() {

        System.out.println("Cat meows: Meow! Meow!");

    }

}


// Child class 3: Bird extends Animal

class Bird extends Animal {

    @Override

    void sound() {

        System.out.println("Bird chirps: Tweet! Tweet!");

    }

}


public class Main {

    public static void main(String[] args) {


        Animal myAnimal;


        myAnimal = new Dog();

        myAnimal.sound();


        myAnimal = new Cat();

        myAnimal.sound();


        myAnimal = new Bird();

        myAnimal.sound();

    }

}

How Method Overriding Works: Polymorphism in Java

This example demonstrates runtime polymorphism beautifully. Even though we use an Animal reference for all objects, the JVM calls the correct method based on the actual object type. When myAnimal points to a Dog object, the Dog's sound() method executes. When it points to a Cat object, the Cat's sound() method executes. This is the power of runtime polymorphism.

Key Points About Method Overriding:

  • The @Override annotation is not required, but it is recommended. This annotation tells the compiler that you are intentionally overriding a method. If you make a mistake, the compiler will alert you.

  • The overridden method in the subclass must have the same signature as the parent class method.

  • You can only override methods, not static methods or final methods.

  • The return type of the overridden method can be a subtype of the parent method's return type (covariant return type).

    Also Explore: Multithreading in Java

Method Overloading vs Method Overriding

Developers often confuse method overloading with method overriding. They are different concepts and serve different purposes. Let's compare them:

FeatureMethod OverloadingMethod Overriding
DefinitionMultiple methods with the same name in the same class but different parametersA subclass provides a new implementation of a method already defined in the parent class
Polymorphism TypeCompile-Time Polymorphism (Static Polymorphism)Runtime Polymorphism (Dynamic Polymorphism)
When It OccursDuring compilationDuring program execution (runtime)
Class RequirementUsually within the same classRequires a parent-child (inheritance) relationship
Method NameMust be the sameMust be the same
Parameter ListMust be different (number, type, or order of parameters)Must be exactly the same as the parent method
Return TypeCan be different (if parameters differ)Must be the same or a compatible (covariant) type
Inheritance RequiredNoYes
PerformanceFaster because method calls are resolved at compile timeSlightly slower because method calls are resolved at runtime
PurposeIncreases method flexibility by handling different inputsAllows subclasses to provide specific behavior
Method ResolutionDecided by the compilerDecided by the JVM at runtime
Binding TypeStatic Binding (Early Binding)Dynamic Binding (Late Binding)

Let's look at an example that shows both concepts:

// Parent class

class Calculation {


    // Method 1: Overloaded method for two integers

    int multiply(int a, int b) {

        return a * b;

    }


    // Method 2: Overloaded method for three integers

    int multiply(int a, int b, int c) {

        return a * b * c;

    }

}


// Child class: Overrides parent method

class AdvancedCalculation extends Calculation {


    // Overrides the first multiply method

    @Override

    int multiply(int a, int b) {

        System.out.println("Advanced calculation for two numbers");

        return a * b + (a + b);

    }

}


public class Main {

    public static void main(String[] args) {


        // Compile-time polymorphism (Method Overloading)

        Calculation calc = new Calculation();

        System.out.println("Multiply 5 and 6: " + calc.multiply(5, 6));

        System.out.println("Multiply 5, 6, and 7: " + calc.multiply(5, 6, 7));


        // Runtime polymorphism (Method Overriding)

        Calculation calc2 = new AdvancedCalculation();

        System.out.println("Advanced multiply 5 and 6: " + calc2.multiply(5, 6));

    }

}

Method Overloading vs Method Overriding

Also Read: Write Your First Java Program: Hello World

Real-World Examples of Polymorphism

Polymorphism is used extensively in real-world applications. Here are some practical examples:

1. Shape Drawing System

Consider a graphics application that needs to draw different shapes. You can have a Shape class with a draw() method. Each shape like Circle, Rectangle, and Triangle overrides this method with its own implementation. The application can call draw() on any Shape reference without knowing the exact type.

abstract class Shape {

    abstract void draw();

}


class Circle extends Shape {

    @Override

    void draw() {

        System.out.println("Drawing a circle");

    }

}


class Rectangle extends Shape {

    @Override

    void draw() {

        System.out.println("Drawing a rectangle");

    }

}


public class Main {

    public static void main(String[] args) {


        Shape shape1 = new Circle();

        shape1.draw();


        Shape shape2 = new Rectangle();

        shape2.draw();

    }

}

Polymorphism in java example: drawing shape system

2. Payment Processing System

A payment application handles different payment methods like Credit Card, Debit Card, and Digital Wallet. Each payment method overrides the pay() method with its own logic. The application processes payments without knowing the specific method.

abstract class PaymentMethod {

    abstract void pay(double amount);

}


class CreditCard extends PaymentMethod {

    @Override

    void pay(double amount) {

        System.out.println("Processing credit card payment of $" + amount);

    }

}


class DigitalWallet extends PaymentMethod {

    @Override

    void pay(double amount) {

        System.out.println("Processing digital wallet payment of $" + amount);

    }

}


public class Main {

    public static void main(String[] args) {


        PaymentMethod payment1 = new CreditCard();

        payment1.pay(100.50);


        PaymentMethod payment2 = new DigitalWallet();

        payment2.pay(250.75);

    }

}

Polymorphism in java example: payment process system

3. Database Operations

In frameworks like Hibernate, polymorphism allows different database types to implement common operations. Each database driver overrides methods to handle database-specific logic while maintaining the same interface.

Advantages of Using Polymorphism

Using polymorphism in your Java code provides many benefits:

1. Code Reusability: You write generic code that works with multiple types. You do not need to duplicate code for different types.

2. Flexibility and Extensibility: You can add new types without changing existing code. This makes your application easier to extend in the future.

3. Loose Coupling: Polymorphism reduces dependencies between classes. Your classes do not need to know the exact type of objects they work with.

4. Better Maintainability: Polymorphic code is cleaner and easier to maintain. Other developers understand the code more quickly.

5. Reduced Complexity: You handle multiple types using a single interface. You avoid complex conditional logic.

6. Better Abstraction: Polymorphism allows you to work with objects at a higher level of abstraction. You focus on what objects do, not how they do it.

7. Improved Testing: Polymorphic code is easier to test. You can create mock objects for testing without changing the main code.

Read Also: Arrays in Java

Best Practices for Implementing Polymorphism

When you use polymorphism in your Java projects, follow these best practices:

1. Use Interfaces for Contracts: Define interfaces or abstract classes to establish contracts. This makes your code more flexible and allows multiple implementations.

2. Follow the Liskov Substitution Principle: Ensure that subclasses can replace parent classes without breaking the code. The behavior should remain consistent.

3. Use the @Override Annotation: Always use the @Override annotation when overriding methods. This helps catch errors during compilation.

4. Prefer Composition Over Inheritance: In some cases, composition (using objects within other objects) is better than inheritance. Choose the right approach for your situation.

5. Keep It Simple: Do not over-engineer your polymorphic design. Use polymorphism only when it makes your code clearer and more maintainable.

6. Document Your Polymorphic Code: Provide clear documentation for your polymorphic classes and methods. This helps other developers understand your design decisions.

7. Test Thoroughly: Test all overloaded and overridden methods thoroughly. Ensure that each implementation works correctly.

8. Avoid Deep Inheritance Hierarchies: Try not to create deep inheritance chains. Keep your class hierarchies shallow and manageable.

Also Explore: Pattern Program in Java (Different Patterns to Practice)

Wrapping Up

Polymorphism is a fundamental concept in Java and object-oriented programming. It enables you to write flexible, reusable, and maintainable code. Java supports two types of polymorphism: compile-time polymorphism through method overloading and runtime polymorphism through method overriding.

Method overloading allows you to create multiple methods with the same name but different parameters. The compiler determines which method to call at compile time. Method overriding allows subclasses to provide their own implementations of parent class methods. The JVM determines which method to call at runtime based on the actual object type.

Understanding polymorphism is essential for becoming a skilled Java developer. It helps you design better applications and write code that other developers can maintain easily. Start using polymorphism in your projects and experience how it improves your code quality.

About the Author
Vaibhav Joshi | Igmguru
About the Author

Vaibhav Joshi has written systems-level and application code in Java, C, and C++ over a career spanning enterprise software and performance-focused projects. Debugging memory issues and bottlenecks under real production load shapes his careful, detail-oriented writing. He tests language and compiler updates directly, helping programmers write efficient, maintainable code.

Drop Us a Query
Fields marked * are mandatory
×

Your Shopping Cart


Your shopping cart is empty.