Polymorphism is one of the building blocks of Object-Oriented Programming (OOP). As the name suggests, polymorphism simply means “many forms.” This feature allows a single method, object, or interface to behave differently in different situations. In this tutorial, we will understand polymorphism with the help of examples.
Let’s say we have a class Animal that has a method sound(). Since Animal is a generic class, we cannot provide a specific implementation such as Roar, Meow, Oink, etc. Instead, we can provide a generic implementation:
public class Animal {
public void sound() {
System.out.println("Animal is making a sound");
}
}
Now let’s say we have two subclasses of the Animal class: Horse and Cat, which extend the Animal class (see Inheritance).
We can provide a different implementation of the same sound() method in each subclass.
For example, the Horse class can override the method as follows:
public class Horse extends Animal {
@Override
public void sound() {
System.out.println("Neigh");
}
}
Similarly, the Cat class can provide its own implementation:
public class Cat extends Animal {
@Override
public void sound() {
System.out.println("Meow");
}
}
As you can see, although sound() is a common action for all subclasses of Animal, different animals perform that action in different ways. A horse makes a Neigh sound, while a cat makes a Meow sound.
This is a perfect example of polymorphism—the ability to perform a single action in different ways.
It would not make much sense to always call the generic sound() method of the Animal class because each animal has its own way of making a sound. Instead, the implementation that gets executed depends on the actual type of object.
In the above example, we can use an Animal reference to refer to different types of objects:
Animal obj = new Horse();
obj.sound(); // Neigh
obj = new Cat();
obj.sound(); // Meow
Here, the reference type is Animal, but the actual object can be a Horse, Cat, or another subclass of Animal. The JVM determines which overridden sound() method should be executed at runtime.
This is known as runtime polymorphism.
What is Polymorphism in Programming?
Polymorphism is the ability of an object to take on different forms and for the same method call to produce different behavior depending on the actual object involved.
In other words, polymorphism allows you to define a common interface or method and provide different implementations of it.
As we saw in the above example, we defined a common sound() method in the Animal class and provided different implementations of that method in its subclasses.
Which implementation of sound() is executed is determined at runtime based on the actual object. Therefore, the above example is an example of runtime polymorphism.
The two main types of polymorphism in Java, along with method overloading and method overriding, are covered in separate tutorials. You can refer to them here:
- Method Overloading in Java — Method overloading is an example of compile-time (static) polymorphism.
- Method Overriding in Java — Method overriding is an example of runtime (dynamic) polymorphism.
- Types of Polymorphism – Runtime and Compile-time — This tutorial covers the different types of polymorphism in detail. I recommend going through method overloading and method overriding before reading this topic.
Let’s look at the complete code.
Example 1: Runtime Polymorphism in Java
Runtime Polymorphism Example:
Animal.java
public class Animal {
public void sound() {
System.out.println("Animal is making a sound");
}
}
Horse.java
public class Horse extends Animal {
@Override
public void sound() {
System.out.println("Neigh");
}
public static void main(String args[]) {
Animal obj = new Horse();
obj.sound();
}
}
Output:
Neigh
In this example, the reference variable obj is of type Animal, but it refers to a Horse object. Therefore, when we call obj.sound(), the overridden sound() method of the Horse class is executed.
Similarly, we can create a Cat object and call its overridden sound() method.
Cat.java
public class Cat extends Animal {
@Override
public void sound() {
System.out.println("Meow");
}
public static void main(String args[]) {
Animal obj = new Cat();
obj.sound();
}
}
Output:
Meow
The important point to understand here is that the method call is made using an Animal reference, but the method implementation that gets executed depends on the actual object (Horse or Cat). This is why it is called runtime polymorphism.
Example 2: Compile-time Polymorphism
Method overloading is an example of compile-time polymorphism.
class Overload {
void demo(int a) {
System.out.println("a: " + a);
}
void demo(int a, int b) {
System.out.println("a and b: " + a + "," + b);
}
double demo(double a) {
System.out.println("double a: " + a);
return a * a;
}
}
class MethodOverloading {
public static void main(String args[]) {
Overload obj = new Overload();
double result;
obj.demo(10);
obj.demo(10, 20);
result = obj.demo(5.5);
System.out.println("O/P : " + result);
}
}
Here, the demo() method is overloaded three times:
- The first method accepts one
intparameter. - The second method accepts two
intparameters. - The third method accepts one
doubleparameter.
When we call demo(), the compiler determines which version of the method should be invoked based on the number and type of arguments passed.
For example:
obj.demo(10); // Calls demo(int)
obj.demo(10, 20); // Calls demo(int, int)
obj.demo(5.5); // Calls demo(double)
This method selection is performed at compile time, which is why method overloading is known as compile-time polymorphism or static polymorphism.
Output:
a: 10
a and b: 10,20
double a: 5.5
O/P : 30.25
Runtime vs Compile-time Polymorphism
In Java, polymorphism is commonly categorized into two types:
- Compile-time polymorphism — achieved through method overloading.
- Runtime polymorphism — achieved through method overriding.
The key difference is when the method to be executed is determined. In method overloading, the compiler determines the appropriate method during compilation. In method overriding, the JVM determines which overridden method to execute at runtime based on the actual object.
tANGENI says
How do you create constructors in a child class, am confused can anybody help please.
Youssef says
you can create constructors in the child class like in any other class, you just can’t override a constructor from another class.
Ramesh says
class abstract Parent{
protected String name;
public Parent(String name){
this.name=name;
}
}
class Child extends Parent{
public Child(String name,int count){
super(name);
}
}
janaki raman m says
sir/madam
i need
a java program two types of polymorphism
1. compile time method overloading and constructor overloading
2. run time method overriding
please urgent
shinam says
what is the exact meaning of super keyword.
and i want simple program which is basd on super keyword only
Chaitanya Singh says
Refer this article: https://beginnersbook.com/2013/04/java-static-class-block-methods-variables/
Venkatesh Reddy Madduri says
Hi Chaitanya,
Thanks for all your efforts for making up this tutorials very precise and clear. Could you check the Rules for Overloading and Rules for Overriding in above post.
In Rules for Overloading point 1 and 4 are contradictory and same as In Rules for Overriding, the point 3 can be altered to support the new feature of covariant return type(JDK 1.5) as per your https://beginnersbook.com/2014/01/difference-between-method-overloading-and-overriding-in-java/
I would like to review this because it will avoid any further confusions for th e readers.
Thanks,
Venkatesh.
Chaitanya Singh says
Thanks Venkatesh!! I have updated the post.
Anup kumar says
very nice explanation…….we clear our doubts very easily.
surbhi says
very clear tutorial. just what we need to understand Java.
Santhosh says
Overloading can take place in the same class or in its sub-class.
What does this mean? Please provide an example.
Sam says
So instead of Animal obj = new Horse(), why can’t we write Horse obj = new Horse() (maybe this cant be done, not sure) , or just call the this.sound() method in main?