The word polymorphism may sound complicated, but the basic idea is actually quite simple.
Polymorphism means "many forms." In Java, it allows the same method or reference to behave differently depending on the object involved.
For example, a Dog and a Cat are both animals, but they make different sounds. We can have one common sound() method, while each animal provides its own implementation.
class Animal {
void sound() {
System.out.println("Animal makes a sound.");
}
}
class Dog extends Animal {
@Override
void sound() {
System.out.println("Dog barks.");
}
}
class Cat extends Animal {
@Override
void sound() {
System.out.println("Cat meows.");
}
}Now we can write:
Animal animal1 = new Dog();
Animal animal2 = new Cat();
animal1.sound();
animal2.sound();Output:
Dog barks.
Cat meows.Notice something interesting here. Both variables have the type Animal, but they refer to different objects.
Java looks at the actual object and calls the appropriate overridden method.
That's the basic idea of polymorphism.
How Does Polymorphism Work?
Let's look at this statement:
Animal animal = new Dog();The left side:
Animal animalis the reference type.
The right side:
new Dog()creates the actual Dog object.
Because Dog extends Animal, an Animal reference can refer to a Dog object.
Now if we call:
animal.sound();Java runs the Dog version of sound().
This is called runtime polymorphism because Java determines which overridden method to execute at runtime.
A Real-World Example
Think about a remote control with a common powerOn() button.
You might use the same button to turn on a TV, a speaker, or an air conditioner. The button is the same, but each device performs a different action when you press it.
Polymorphism works in a similar way.
We can have:
Vehicle
↓
start()
↙ ↘
Car Bike
↓ ↓
start() start()The method name is the same, but each object can behave differently.
For example:
class Vehicle {
void start() {
System.out.println("Vehicle starts.");
}
}
class Car extends Vehicle {
@Override
void start() {
System.out.println("Car starts.");
}
}
class Bike extends Vehicle {
@Override
void start() {
System.out.println("Bike starts.");
}
}Now:
Vehicle vehicle1 = new Car();
Vehicle vehicle2 = new Bike();
vehicle1.start();
vehicle2.start();Output:
Car starts.
Bike starts.The same start() call produces different behavior depending on the object.
Polymorphism with a Collection
Polymorphism becomes especially useful when we have multiple objects of different child classes.
For example:
Animal[] animals = {
new Dog(),
new Cat(),
new Dog()
};
for (Animal animal : animals) {
animal.sound();
}Output:
Dog barks.
Cat meows.
Dog barks.The loop doesn't need to know whether each object is a Dog or a Cat. It simply knows that every object is an Animal and has a sound() method.
Java automatically calls the appropriate version for each object.
This is one of the biggest advantages of polymorphism: we can write more flexible code that works with different types of objects.
Types of Polymorphism
Java mainly has two forms of polymorphism that you'll commonly hear about:
Compile-time polymorphism is commonly achieved through method overloading.
void add(int a, int b) {
}
void add(int a, int b, int c) {
}Java determines which method to call based on the arguments provided.
Runtime polymorphism is achieved through method overriding.
Animal animal = new Dog();
animal.sound();Java determines which overridden method to execute based on the actual object.
So you can remember:
Overloading → Compile-time polymorphism
Overriding → Runtime polymorphism
Polymorphism and Inheritance
Polymorphism is closely connected to inheritance.
For example:
Animal
├── Dog
└── CatBecause Dog and Cat inherit from Animal, we can use an Animal reference to refer to either one:
Animal a1 = new Dog();
Animal a2 = new Cat();Then:
a1.sound();
a2.sound();Each object behaves according to its own implementation.
The Main Idea
Don't let the word polymorphism scare you. The core idea is simply:
One common interface or reference, but different behavior depending on the actual object.
For example:
Animal animal = new Dog();
animal.sound();The reference is Animal, but the object is Dog, so the Dog version of sound() runs.
Once you understand inheritance and method overriding, polymorphism becomes much easier to understand. It allows Java programs to work with different types of objects in a flexible and reusable way.