Polymorphism is a fundamental concept in Object-Oriented Programming (OOP), including Java, that allows one object to take on multiple forms. In simpler terms, polymorphism enables objects of different classes to be treated as objects of a common superclass. It also allows the same method or operation to behave differently based on the object that is calling it.
Polymorphism is derived from two Greek words: poly (meaning “many”) and morph (meaning “form”). So, polymorphism means “many forms.”
Types of Polymorphism in Java
In Java, there are two main types of polymorphism:
- Compile-Time Polymorphism (also known as Method Overloading)
- Run-Time Polymorphism (also known as Method Overriding)
1. Compile-Time Polymorphism (Method Overloading)
Compile-time polymorphism is achieved through method overloading. In method overloading, multiple methods in the same class have the same name but differ in their parameters (i.e., number or type of arguments). The method that gets called is determined at compile time based on the number or type of arguments.
Example of Compile-Time Polymorphism (Method Overloading):
class Calculator {
// Method to add two integers
public int add(int a, int b) {
return a + b;
}
// Method to add three integers
public int add(int a, int b, int c) {
return a + b + c;
}
// Method to add two double numbers
public double add(double a, double b) {
return a + b;
}
}
public class Main {
public static void main(String[] args) {
Calculator calculator = new Calculator();
// Calling overloaded methods
System.out.println(calculator.add(2, 3)); // Output: 5
System.out.println(calculator.add(2, 3, 4)); // Output: 9
System.out.println(calculator.add(2.5, 3.5)); // Output: 6.0
}
}
In this example:
- The
add()
method is overloaded with different parameter types and counts. - The correct method is called based on the parameters passed at compile time.
2. Run-Time Polymorphism (Method Overriding)
Run-time polymorphism is achieved through method overriding. Method overriding occurs when a subclass provides a specific implementation of a method that is already defined in its superclass. The decision of which method to invoke is made at runtime, based on the actual object that calls the method.
Example of Run-Time Polymorphism (Method Overriding):
class Animal {
// Method in parent class
public void sound() {
System.out.println("Some animal sound");
}
}
class Dog extends Animal {
// Overriding the sound() method in the Dog class
@Override
public void sound() {
System.out.println("Bark");
}
}
class Cat extends Animal {
// Overriding the sound() method in the Cat class
@Override
public void sound() {
System.out.println("Meow");
}
}
public class Main {
public static void main(String[] args) {
Animal myAnimal = new Animal(); // Parent class object
Animal myDog = new Dog(); // Child class object (Dog)
Animal myCat = new Cat(); // Child class object (Cat)
// Calling the overridden method based on the object type
myAnimal.sound(); // Output: Some animal sound
myDog.sound(); // Output: Bark
myCat.sound(); // Output: Meow
}
}
In this example:
- The
sound()
method is defined in theAnimal
class. - Both
Dog
andCat
classes override thesound()
method with their own implementation. - When
sound()
is called on objects of typeAnimal
, the specific method for the actual object (Dog
orCat
) is called at runtime, demonstrating run-time polymorphism.
Why is Polymorphism Important?
Polymorphism is important for several reasons:
- Code Reusability: It allows for code reuse. With polymorphism, the same method or function can be used with different types of objects, which reduces redundancy.
- Flexibility: Polymorphism allows a more flexible code structure, as methods can behave differently depending on the object type.
- Maintainability: With polymorphism, it’s easier to maintain and extend code. You can add new classes that implement the same interface or inherit from the same parent class without modifying existing code.
- Decoupling: It promotes decoupling between classes and methods. You don’t need to know the exact type of an object to use it, just the methods it supports.
Example of Polymorphism in Action (Using Interfaces):
You can also use polymorphism with interfaces. Here’s an example:
interface Animal {
void sound();
}
class Dog implements Animal {
@Override
public void sound() {
System.out.println("Bark");
}
}
class Cat implements Animal {
@Override
public void sound() {
System.out.println("Meow");
}
}
public class Main {
public static void main(String[] args) {
Animal myAnimal = new Dog(); // Animal type reference
myAnimal.sound(); // Output: Bark
myAnimal = new Cat(); // Changing the object to Cat
myAnimal.sound(); // Output: Meow
}
}
In this case:
- Both
Dog
andCat
classes implement theAnimal
interface. - The
sound()
method is called polymorphically, with the behavior determined at runtime based on the object (Dog
orCat
) assigned to theAnimal
reference.
Summary
- Polymorphism in Java allows a single interface or method to represent different underlying forms or behaviors.
- Compile-time polymorphism (method overloading) is resolved during the compilation phase, and involves defining multiple methods with the same name but different parameter types.
- Run-time polymorphism (method overriding) is resolved during runtime, and occurs when a subclass provides a specific implementation of a method defined in the parent class.
- Polymorphism helps to achieve code reusability, flexibility, and maintainability in Java programs.
Understanding polymorphism is key to mastering object-oriented programming, as it allows you to write more efficient, flexible, and scalable code.