Polymorphism in Java
On Day 10, we will explore the concept of Polymorphism, one of the four pillars of Object-Oriented Programming (OOPs). Polymorphism enables Java objects to take multiple forms, allowing for flexible and dynamic code. It plays a crucial role in improving code maintainability and reusability by providing a way to perform a single action in different ways.
1. What is Polymorphism?
Polymorphism in Java allows one interface to be used for a general class of actions. The specific action is determined by the exact nature of the situation. The term "polymorphism" is derived from two Greek words:
Poly: Many
Morph: Forms
In Java, polymorphism manifests primarily in two forms:
Compile-time (Static) Polymorphism – Achieved through method overloading.
Run-time (Dynamic) Polymorphism – Achieved through method overriding.
2. Types of Polymorphism
A. Compile-time Polymorphism (Method Overloading)
Compile-time polymorphism occurs when multiple methods share the same name but differ in:
The number of parameters.
The type of parameters.
This is also known as method overloading. The method to be called is determined at compile-time based on the method signature.
Method Overloading Example:
class Calculator {
// Method to add two integers
public int add(int a, int b) {
return a + b;
}
// Overloaded method to add three integers
public int add(int a, int b, int c) {
return a + b + c;
}
// Overloaded method to add two doubles
public 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(calc.add(2, 3)); // Calls add(int, int)
System.out.println(calc.add(2, 3, 4)); // Calls add(int, int, int)
System.out.println(calc.add(2.5, 3.5)); // Calls add(double, double)
}
}
Explanation:
In the example above, the
add()
method is overloaded three times with different parameter lists.Depending on the number and type of arguments passed, the appropriate
add()
method is invoked at compile-time.
B. Run-time Polymorphism (Method Overriding)
Run-time polymorphism occurs when a method is overridden in a subclass, and the method that gets executed is determined at run-time based on the object type (not the reference type). This is also known as method overriding.
To achieve run-time polymorphism, the following conditions must be met:
The method in the subclass must have the same name, return type, and parameters as the method in the superclass.
There must be inheritance (i.e., the subclass should inherit the superclass).
Method overriding enables dynamic method dispatch where the method called depends on the object type, not the reference type.
Method Overriding Example:
class Animal {
// Overridden method
public void sound() {
System.out.println("This animal makes a sound.");
}
}
class Dog extends Animal {
// Overriding the sound method
@Override
public void sound() {
System.out.println("The dog barks.");
}
}
class Cat extends Animal {
// Overriding the sound method
@Override
public void sound() {
System.out.println("The cat meows.");
}
}
public class Main {
public static void main(String[] args) {
Animal myAnimal = new Animal(); // Animal object
Animal myDog = new Dog(); // Dog object
Animal myCat = new Cat(); // Cat object
myAnimal.sound(); // Calls Animal's sound method
myDog.sound(); // Calls Dog's sound method
myCat.sound(); // Calls Cat's sound method
}
}
Explanation:
In this example, the
sound()
method is overridden in both theDog
andCat
classes.Although the reference type is
Animal
, the actual method that gets invoked at run-time is based on the object type (Dog
orCat
).
3. Dynamic Method Dispatch
Dynamic Method Dispatch is the process by which a call to an overridden method is resolved at run-time rather than compile-time. This is a key aspect of run-time polymorphism in Java.
Upcasting: In run-time polymorphism, a reference of the superclass can point to an object of the subclass. This is called upcasting.
The method that gets called is determined by the actual object (subclass), not the reference type (superclass).
Example of Dynamic Method Dispatch:
class Animal {
public void sound() {
System.out.println("This animal makes a sound.");
}
}
class Dog extends Animal {
@Override
public void sound() {
System.out.println("The dog barks.");
}
}
class Cat extends Animal {
@Override
public void sound() {
System.out.println("The cat meows.");
}
}
public class Main {
public static void main(String[] args) {
Animal animal; // Superclass reference
animal = new Dog(); // Reference points to Dog object
animal.sound(); // Calls Dog's sound method
animal = new Cat(); // Reference points to Cat object
animal.sound(); // Calls Cat's sound method
}
}
Explanation:
- In this case, the reference type is
Animal
, but at run-time, the method of the actual object (Dog
orCat
) is invoked. This is dynamic method dispatch.
4. Polymorphism with Interfaces
Polymorphism is also achieved through interfaces in Java. An interface defines a contract, and multiple classes can implement this interface in their own way. This allows you to treat different classes in a uniform way, as long as they implement the same interface.
Example of Polymorphism with Interfaces:
interface Animal {
void sound();
}
class Dog implements Animal {
@Override
public void sound() {
System.out.println("The dog barks.");
}
}
class Cat implements Animal {
@Override
public void sound() {
System.out.println("The cat meows.");
}
}
public class Main {
public static void main(String[] args) {
Animal animal = new Dog(); // Dog implements Animal
animal.sound(); // Calls Dog's implementation
animal = new Cat(); // Cat implements Animal
animal.sound(); // Calls Cat's implementation
}
}
Explanation:
The
Dog
andCat
classes implement theAnimal
interface, and thesound()
method is overridden in both classes.Polymorphism allows the same interface reference (
Animal
) to be used to point to different object types (Dog
orCat
).
5. Advantages of Polymorphism
Flexibility: Code can work with objects of different classes, even if they behave differently, making the system more flexible.
Code Reusability: You can write more generic and reusable code, as the same code can work for objects of different types.
Maintainability: Adding new types that conform to the existing system does not require changes to the polymorphic code.
Extensibility: New classes can be added without modifying existing classes, making the system more extensible.
6. Key Points to Remember
Overloading (Compile-time polymorphism): Same method name with different signatures (number, type of parameters).
Overriding (Run-time polymorphism): Same method signature in superclass and subclass, where the subclass provides a specific implementation.
Dynamic Method Dispatch: At run-time, the method of the actual object type is invoked, not the reference type.
Polymorphism with Interfaces: Different classes can implement the same interface, allowing uniformity in code.
Summary
By the end of Day 10, we will have a deep understanding of:
What polymorphism is and why it’s important in Java.
How to achieve compile-time polymorphism using method overloading.
How to implement run-time polymorphism using method overriding.
The role of dynamic method dispatch in method resolution.
How to use interfaces to implement polymorphism in a structured and flexible way.
Polymorphism is a powerful concept that allows Java programs to be more dynamic, flexible, and maintainable, making it an essential part of mastering Object-Oriented Programming. So Stay tuned!! for further topics.
Subscribe to my newsletter
Read articles from Mohit Upadhyay directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by