Polymorphism in Java
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 word "polymorphism" means "many forms," and it occurs when we have many classes that are related to each other by inheritance.
Polymorphism is one of the core principles of Object-Oriented Programming (OOP) that allows objects to be treated as instances of their parent class rather than their actual class.
This enables flexibility and integration of different classes through a common interface.
Types of Polymorphism
Compile-time Polymorphism (Static Binding): Achieved by method overloading.
Runtime Polymorphism (Dynamic Binding): Achieved by method overriding.
Method Overloading (Compile-time Polymorphism)
Method overloading allows a class to have more than one method with the same name, provided their parameter lists are different.
It is resolved during compile time.
Example of Method Overloading
class MathUtils {
// 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 double values
public double add(double a, double b) {
return a + b;
}
}
public class Main {
public static void main(String[] args) {
MathUtils math = new MathUtils();
System.out.println(math.add(5, 3)); // Outputs 8
System.out.println(math.add(5, 3, 2)); // Outputs 10
System.out.println(math.add(5.5, 3.3)); // Outputs 8.8
}
}
Method Overriding (Runtime Polymorphism)
Method overriding allows a subclass to provide a specific implementation of a method that is already defined in its superclass.
It is resolved during runtime.
Example of Method Overriding
class Animal {
// Method to be overridden
public void sound() {
System.out.println("Animal makes a sound");
}
}
class Dog extends Animal {
// Overriding the sound method
@Override
public void sound() {
System.out.println("Dog barks");
}
}
class Cat extends Animal {
// Overriding the sound method
@Override
public void sound() {
System.out.println("Cat meows");
}
}
public class Main {
public static void main(String[] args) {
Animal myAnimal = new Animal(); // Animal reference and object
Animal myDog = new Dog(); // Animal reference but Dog object
Animal myCat = new Cat(); // Animal reference but Cat object
myAnimal.sound(); // Outputs: Animal makes a sound
myDog.sound(); // Outputs: Dog barks
myCat.sound(); // Outputs: Cat meows
}
}
Explanation:
Superclass (Animal): Contains the method sound().
Subclass (Dog): Overrides the sound() method to provide its specific implementation.
Subclass (Cat): Also overrides the sound() method to provide its specific implementation.
Using Polymorphism: The sound() method call is resolved at runtime based on the actual object type (Dog or Cat), not the reference type (Animal).
Advantages of Polymorphism
Flexibility: Write more generic and reusable code.
Maintainability: Easier to maintain and extend code as new classes can be added with minimal changes to existing code.
Interchangeability: Objects can be replaced or interchanged without affecting the overall system behavior.
Polymorphism in Action: Real-world Example
Consider a scenario where we have a base class Employee and derived classes Manager and Developer. Each class will have a method work() that is implemented differently.
class Employee {
public void work() {
System.out.println("Employee is working");
}
}
class Manager extends Employee {
@Override
public void work() {
System.out.println("Manager is managing the team");
}
}
class Developer extends Employee {
@Override
public void work() {
System.out.println("Developer is writing code");
}
}
public class Main {
public static void main(String[] args) {
Employee emp1 = new Manager();
Employee emp2 = new Developer();
emp1.work(); // Outputs: Manager is managing the team
emp2.work(); // Outputs: Developer is writing code
}
}
Explanation:
Superclass (Employee): Contains the method work().
Subclass (Manager): Overrides the work() method to provide its specific implementation.
Subclass (Developer): Also overrides the work() method to provide its specific implementation.
Using Polymorphism: The work() method call is resolved at runtime based on the actual object type (Manager or Developer), not the reference type (Employee).
Summary
Polymorphism: The ability of an object to take on many forms, allowing objects of different classes to be treated through the same interface.
Compile-time Polymorphism: Achieved by method overloading, resolved at compile time.
Runtime Polymorphism: Achieved by method overriding, resolved at runtime.
Advantages: Provides flexibility, maintainability, and interchangeability in code.
Real-world Example: Demonstrates how polymorphism can be applied to model real-world scenarios effectively.
Understanding polymorphism is crucial for writing flexible and maintainable object-oriented code in Java.