Java Polymorphism


Polymorphism is one of the key principles of Object-Oriented Programming (OOP) in Java that allows objects to be treated as instances of their parent class, enabling a single interface to represent different underlying forms (data types). The term "polymorphism" means "many shapes" and refers to the ability of a method or an object to take many forms.

Types of Polymorphism in Java

  1. Compile-time Polymorphism (Static Polymorphism):

    • Achieved through method overloading and operator overloading.
    • Involves defining multiple methods with the same name but different parameter lists (type, number, or both).
  2. Runtime Polymorphism (Dynamic Polymorphism):

    • Achieved through method overriding, where a subclass provides a specific implementation of a method that is already defined in its superclass.
    • The decision about which method to invoke is made at runtime based on the object type.

1. Compile-time Polymorphism

Method Overloading

In method overloading, multiple methods can have the same name but must differ in the type or number of parameters. The correct method to be called is determined at compile time.

Example of Method Overloading:

class MathOperations { // Method to add two integers int add(int a, int b) { return a + b; } // Overloaded method to add three integers int add(int a, int b, int c) { return a + b + c; } // Overloaded method to add two double values double add(double a, double b) { return a + b; } } // Main class to demonstrate method overloading public class Main { public static void main(String[] args) { MathOperations math = new MathOperations(); System.out.println(math.add(5, 10)); // Output: 15 System.out.println(math.add(5, 10, 15)); // Output: 30 System.out.println(math.add(5.5, 10.5)); // Output: 16.0 } }

Explanation:

  • The MathOperations class contains three overloaded add methods. The appropriate method is selected at compile time based on the arguments passed.

2. Runtime Polymorphism

Method Overriding

In method overriding, a subclass provides a specific implementation of a method that is already defined in its superclass. The method invoked is determined at runtime based on the object type, allowing for dynamic behavior.

Example of Method Overriding:

// Superclass class Animal { void sound() { System.out.println("Animal makes a sound."); } } // Subclass class Dog extends Animal { @Override void sound() { System.out.println("Dog barks."); } } // Another subclass class Cat extends Animal { @Override void sound() { System.out.println("Cat meows."); } } // Main class to demonstrate runtime polymorphism public class Main { public static void main(String[] args) { Animal myAnimal; // Declare a reference variable of type Animal // Create a Dog object and assign it to the Animal reference myAnimal = new Dog(); myAnimal.sound(); // Output: Dog barks. // Create a Cat object and assign it to the Animal reference myAnimal = new Cat(); myAnimal.sound(); // Output: Cat meows. } }

Explanation:

  • In this example, the Animal class has a method sound(), which is overridden in both the Dog and Cat subclasses.
  • The variable myAnimal is of type Animal, but it can reference any object that is a subclass of Animal.
  • When myAnimal.sound() is called, the JVM determines which method to execute at runtime based on the actual object type, not the reference type.

Advantages of Polymorphism:

  1. Code Reusability: Allows methods to be reused across different classes with similar behaviors, reducing code duplication.
  2. Flexibility and Extensibility: New subclasses can be added with specific behaviors without modifying existing code, making it easier to extend and maintain.
  3. Dynamic Method Binding: Supports runtime polymorphism, where the method to be executed is determined at runtime, allowing for dynamic and flexible code execution.

Summary:

  • Polymorphism allows objects to be treated as instances of their parent class, enabling multiple forms and enhancing code flexibility.
  • Compile-time polymorphism is achieved through method overloading, while runtime polymorphism is achieved through method overriding.
  • Polymorphism is a powerful feature in Java that promotes code reusability, flexibility, and maintainability, allowing developers to create more dynamic and modular applications.