Java Polymorphism

Polymorphism is a fundamental concept in Object-Oriented Programming (OOP) that allows one entity (such as a method or object) to take many forms. In Java, polymorphism enables you to use a single method, operator, or class to perform different tasks depending on the context.

There are two main types of polymorphism in Java

1. Compile-time Polymorphism (Static Polymorphism)

2. Runtime Polymorphism (Dynamic Polymorphism)

1. Compile-time Polymorphism (Static Polymorphism)

Compile-time polymorphism, also known as method overloading, occurs when two or more methods in the same class have the same name but different parameters (either in number or type). The method to be invoked is determined at compile time.

Example:


class Calculator {
    // Method to add two integers
    int add(int a, int b) {
        return a + b;
    }

    // Method to add three integers
    int add(int a, int b, int c) {
        return a + b + c;
    }

    // Method to add two double values
    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(10, 20));        // Calls the method with two integers
        System.out.println(calc.add(10, 20, 35));    // Calls the method with three integers
        System.out.println(calc.add(10.5, 20.4));    // Calls the method with two doubles
    }
}

Output:

30
65
30.9

Explanation:

In this example, the add() method is overloaded to accept different numbers and types of arguments, demonstrating compile-time polymorphism.

2. Runtime Polymorphism (Dynamic Polymorphism)

Runtime polymorphism, also known as method overriding, occurs when a subclass provides a specific implementation of a method that is already defined in its superclass. The method to be invoked is determined at runtime, not at compile time.


// Parent class
class Vehicle {
    void usefuel() {
        System.out.println("Vehicle use many type of fuels.");
    }
}

// Child class
class PetrolCar extends Vehicle {
    @Override
    void usefuel() {
        System.out.println("Petrol car use petrol fuel to run.");
    }
}

// Child class
class DieselCar extends Vehicle {
    @Override
    void usefuel() {
        System.out.println("Diesel car use diesel fuel to run.");
    }
}

class ElectricCar extends Vehicle {
    @Override
    void usefuel() {
        System.out.println("Electric car does not use fuel.");
    }
}

public class Main {
    public static void main(String[] args) {

        // PetrolCar object assigned to Vehicle reference
        PetrolCar petrolCar = new PetrolCar();
        petrolCar.usefuel();  // Outputs: Petrol car use petrol fuel to run.

        // DieselCar object assigned to Vehicle reference
        DieselCar dieselCar = new DieselCar();
        dieselCar.usefuel();  // Outputs: Diesel car use diesel fuel to run
        
        // ElectricCar object assigned to Vehicle reference
        ElectricCar electricCar = new ElectricCar();
        electricCar.usefuel();  // Outputs: Electric car does not use fuel.
    }
}

Output:

Petrol car use petrol fuel to run.
Diesel car use diesel fuel to run.
Electric car does not use fuel.

Explanation of Example:

  1. Vehicle class defines a method usefuel().
  2. PetrolCar, DieselCar and ElectricCar classes override the usefuel() method.
  3. At runtime, the usefuel() method of the appropriate class (PetrolCar or DieselCar or ElectricCar) is invoked, demonstrating runtime polymorphism.

Advantages of Polymorphism

1. Flexibility and Reusability: You can use the same method or operator to work with different types of objects, enhancing code reuse and flexibility.

2. Ease of Maintenance: By using polymorphism, you can modify the behavior of a method in subclasses without changing the method’s invocation code.

3. Decoupling: Polymorphism allows you to write code that works with superclass references, and the actual object being used can be of any subclass type.