Polymorphism is a fundamental concept in object-oriented programming (OOP). Since Java is an OOP language, it fully supports polymorphism, which allows developers to write more flexible, efficient, and reusable code.
The term polymorphism comes from two Greek words: poly (meaning "many") and morph (meaning "form"). So, polymorphism literally means "many forms," a single object can take on multiple forms or behaviors.
Example -
Consider a person named Ayush. At home, he acts as a teacher, helping his children study. At the office, he becomes an employee, fulfilling tasks assigned by his manager. On weekends, he participates in cultural programs as a dancer. Though Ayush is one individual, his behavior changes based on the situation. Similarly, in Java, a single object can perform different behaviors depending on how it is used, which can be achieved through method overloading or method overriding.
Types Of Polymorphism
Compile Time Polymorphism
Run Time Polymorphism
Compile Time Polymorphism
Compile time polymorphism is also known as static or early binding. It occurs when the decision about which method to call is made at compile time.
Example - Method overloading
Run Time Polymorphism
Run time polymorphism is also known as dynamic or late binding. It occurs when the decision about which method to call is made at run time.
Example- Method Overriding
Compile Time vs Run Time Polymorphism
What is Method Overloading?
Developing multiple methods with the same name by variation in the arguments list is called method overloading.
Variation in the argument lists means variation in the number of arguments, the datatype of the arguments, and the position of the arguments.
Both static and non-static methods can be overloaded.
Two method is said to be overloaded if both the method having same name but variation in arguments such as number of arguments, datatype of the arguments and the position of the arguments.
Syntax
returnType methodName(parameterType1 param1) {
// method body
}
returnType methodName(parameterType1 param1, parameterType2 param2) {
// method body
}
returnType methodName(parameterType1 param1, parameterType2 param2, parameterType3 param3) {
// method body
}
Example
public class MasterBackend {
// sum method with two int parameters
public int sum(int a, int b) {
return a + b;
}
// sum method with three int parameters
public int sum(int a, int b, int c) {
return a + b + c;
}
// sum method with two double parameters
public double sum(double a, double b) {
return a + b;
}
public static void main(String[] args) {
MasterBackend obj = new MasterBackend();
System.out.println("Sum of 10 and 20: " + obj.sum(10, 20));
System.out.println("Sum of 10, 20 and 30: " + obj.sum(10, 20, 30));
System.out.println("Sum of 10.5 and 20.5: " + obj.sum(10.5, 20.5));
}
}
Here, in this example, inside the MasterBackend class, we develop several methods with the same name but variations in parameters. But all the methods perform the same operation, which is addition. In the first method, we add two Integer numbers, and in the second method, we add three Integer numbers; then, in the third method, we add two double numbers, that’s why we give the same name. By giving the same name, we can remember the method names easily, and Compile time polymorphism occurs when the decision about which method to call is made at compile time according to the parameters.
Output
Sum of 10 and 20: 30
Sum of 10, 20 and 30: 60
Sum of 10.5 and 20.5: 31.0
What is Method Overriding?
Method overriding is a mechanism that enables runtime polymorphism in Java.
It occurs when a subclass provides a specific implementation of a method that is already defined in its superclass.
Inheritance is essential for method overriding, as the method in the subclass must originate from a superclass.
The method signature (name, parameters, and order) in the subclass must be identical to that of the superclass.
Static and private methods cannot be overridden because:
Static methods belong to the class, not instances.
Private methods are not inherited by subclasses.
Method overriding is commonly used in abstract classes and interfaces, where child classes are required to provide specific implementations for abstract methods.
The
@Override
annotation is used to:Indicate that a method is intended to override a superclass method.
Help catch errors at compile time if the method signature doesn’t match.
In simple terms:
When a child (or subclass) is not satisfied with the behavior of a method inherited from the parent (superclass), it can override that method to provide a new implementation. This is known as method overriding.
Syntax
// Superclass class SuperClass { returnType methodName(parameterType1 param1, parameterType2 param2) { // method body } } // Subclass class SubClass extends SuperClass { @Override returnType methodName(parameterType1 param1, parameterType2 param2) { // overridden method body }
Here,
@Override
annotation for better readability and compile-time checking.Example
class Person { public void smoking() { System.out.println("Person may or may not smoke."); } } class Teenager extends Person { @Override public void smoking() { System.out.println("Teenager should avoid smoking."); } } // Main class public class MasterBackend { public static void main(String[] args) { Person p1 = new Person(); Person p2 = new Teenager(); p1.smoking(); p2.smoking(); } }
In this example, we have a superclass called
Person
and a subclass namedTeenager
. Both classes define a method with the same name and signature:smoking()
. However, each class provides its own implementation. ThePerson
class offers a general statement about smoking, while theTeenager
class overrides the method to deliver a more specific message. We use the same method name because the action being performed is conceptually the same, communicating a message about smoking, but the behavior varies depending on the object type. This illustrates runtime polymorphism, where the decision about which method to invoke is made at runtime, based on the actual object instance rather than the reference type.Output
Person may or may not smoke. Teenager should avoid smoking.
Example 2
class Vehicle { void start() { System.out.println("The vehicle starts"); } } class Car extends Vehicle { @Override void start() { System.out.println("The car starts with a key ignition"); } } class Bike extends Vehicle { @Override void start() { System.out.println("The bike starts with a kick"); } } public class Main { public static void main(String[] args) { Vehicle myVehicle = new Vehicle(); myVehicle.start(); // Calls the start method in Vehicle Vehicle myCar = new Car(); myCar.start(); // Calls the overridden start method in Car Vehicle myBike = new Bike(); myBike.start(); // Calls the overridden start method in Bike } }
In this example,
Vehicle
is the superclass that defines a method namedstart()
. The classesCar
andBike
extendVehicle
and override thestart()
method to provide behavior specific to their types. At runtime, the actual object type (whether it's aCar
,Bike
, orVehicle
) determines which version of thestart()
method is executed. This demonstrates runtime polymorphism, where method resolution is deferred until the program is running and depends on the object's actual class, not the reference type.Output
The vehicle starts The car starts with a key ignition The bike starts with a kick
Overloading Vs Overriding
Method Overloading
Occurs within the same class
Same method name but different parameter list
Return type can be different (if the parameter list is different)
No inheritance required
Compile-time polymorphism (resolved at compile time)
Increases code readability and reusability
No @Overloding annotation used
Method resolution happens by checking the method signature
Method Overriding
Occurs in a subclass (child class) only
Same method name and same parameter list as in the superclass
Return type must be the same or covariant
Requires inheritance
Runtime polymorphism (resolved at runtime)
Used to provide a specific implementation of a method
Uses @Override annotation (recommended)
Method resolution depends on the object’s runtime type
Frequently Asked Questions
Can we override the static methods?
No. We can’t override static methods because static methods will not be inherited by the subclass. And to achieve method overriding, inheritance is mandatory.
Can we overload the main method?
Yes. We can overload the main method, but the JVM only take that method which is having the String args[] as the parameter.
Can we override the main method?
No. Because the main method is a static method and static method will not be inherited by the subclass. And to achieve method overriding, inheritance is mandatory.
Can we override the constructor?
No. Because the constructor will not be inherited by subclass. and to achieve method overriding, inheritance is mandatory.