What is Polymorphism in OOPS?

What is Polymorphism in OOPS?

Welcome to polymorphic world of OOP

Polymorphism is one of the core concepts of object-oriented programing. Polymorphism enables developers to write flexible and dynamic code that interacts seamlessly with diverse object types. The meaning of polymorphism is hidden in the word itself. If we split the word polymorphism, we get "Poly" means many and "Morph" means forms. Meaning it is the ability of an object to take many forms. It describes the concept that you can access objects of different types using the same interface. Each type can provide its own independent implementation of the interface. The kind of polymorphism an object undergo depends upon when the object takes its form and what part of the object is transforming.

When the object transforms:

  1. Compile-Time

  2. Runtime

What does the transforming:

  1. Method

  2. Object

There are four types of polymorphism.

  1. Ad-Hoc / Static / Compile-Time / Method overloading

  2. Inclusion / Subtyping / Dynamic or Runtime / Method overriding

  3. Parametric

  4. Coercion / Casting

Let's look at each one by one with an example.

Ad-hoc / Static/ Compile-Time / Method overloading

In this type of polymorphism, the function with the same name acts differently for different types of arguments. It is also called static or compile-time polymorphism because we are writing two static implementations of the same method and the compiler is not complaining at all. It is achieved via method overloading. Let's understand with an example.

class Adder {
    static int add(int a, int b) {
        return a + b;
    }

    static double add(double a, double b) {
        return a + b;
    }
}

class Main {
    public static void main(String[] args) {
        System.out.println(Adder.add(11, 11)); // O/P: 22

        System.out.println(Adder.add(12.3, 12.6)); // O/P: 24.9
    }
}

The class adder has two methods with the same name but different signatures. There are two overloaded methods, one with the parameter of type integer and the other with the parameter of type double. Now, look at the main method of the Main class. We are invoking add method of the adder class by passing arguments of type integers and it is choosing the right method which matches the integer type arguments with the method signature. Similarly, We are invoking add method of the adder class by passing arguments of type double and it is also choosing the right method which matches the double type arguments with the method signature.

Inclusion / Subtyping / Dynamic or Runtime / Method overriding

This is the most common type of polymorphism. In this type of polymorphism, we are using the reference variable of the parent class to store various child objects of the parent class. The compiler does not need to know which implementation to use, it can be resolved at runtime. It's achieved using method overriding. Within an inheritance hierarchy, a child class can override a method of its parent class, enabling the developer of the child class to customize or completely replace the behavior of that method. Let's understand with an example.

public class Vehicle {
    void run(){
        System.out.println("Vehicle is moving");
    }
}

public class Bicycle extends Vehicle {
    @Override
    void run() {
        System.out.println("Bicycle is moving");
    }
}

public class Car extends Vehicle {
    @Override
    void run() {
        System.out.println("Car is moving");
    }
}

public class Truck extends Vehicle {
    @Override
    void run() {
        System.out.println("Truck is moving");
    }
}

public class Main {
    public static void main(String[] args) {
       Vehicle obj = new Car();
       obj.run(); // o/p: Car is moving

       obj = new Truck();
       obj.run(); // o/p: Truck is moving
    }
}

Here we are overriding the run method of the parent class in each base class to give a specific implementation based on the vehicle type. Look at the last 4 lines of code, we are creating a new object of Car and storing it in a variable that is of parent type. We are sharing the same interface with the parent class which is why we are able to assign child class objects to the parent class variable. When we call the run method on the car object it will output "Car is moving", Then we are swapping the implementation at runtime with the truck object. This all happens at runtime which is why it is called Runtime Polymorphism. Now, the obj variable stores the object of the class truck, and on calling the run method on a truck object, it will output "Truck is moving". It demonstrates that variable obj is taking different forms at different points in time.

Parametric

Parametric polymorphism is when code is written without knowing the type of the arguments. This type of code is called parametric code because it depends on the type of the arguments. Polymorphic functions in Java and generics in Java are just two great examples. Let's understand with an example.

public class Vehicle {
    void run(){
        System.out.println("Vehicle is moving");
    }
}

public class Bicycle extends Vehicle {
    @Override
    void run() {
        System.out.println("Bicycle is moving");
    }
}

public class Car extends Vehicle {
    @Override
    void run() {
        System.out.println("Car is moving");
    }
}

public class Truck extends Vehicle {
    @Override
    void run() {
        System.out.println("Truck is moving");
    }
}

public class Main {
    public static void main(String[] args) {
       Vehicle obj = new Car();
       printRunningStatus(obj); // o/p: Car is moving
       obj = new Bicycle();
       printRunningStatus(obj); // o/p: Bicycle is moving

        // Generics
        List<Vehicle> vehicles = new ArrayList<Vehicle>();

        vehicles.add(new Bicycle());
        vehicles.add(new Car());
        vehicles.add(new Truck());

        for (Vehicle obj: vehicles) {
            obj.run();
        }
    }

    public static void printRunningStatus(Vehicle obj) {
        obj.run();
    }
}

Here printRunningStatus is written without knowing the type of argument. It accepts all the subtype objects of the vehicle class. It helps developers to write flexible software where methods can behave differently based on different types of arguments it receives.

If we look at the generic ArrayList, it is designed without the knowledge of the type of arguments it receives. We can add any type of vehicle to it, and iterate through it without knowing the type of objects it stores. It allows developers to code that works with any type of object hence increasing the reusability of the code.

Coercion / Casting

Many programming languages allow the conversion of one data type to another data type. The kind of conversion may be Implicit or Explicit. Implicit coercion is automatically done by JVM but explicit coercion is done by the programmers. The mechanism of converting one type of object to another object of a different type with similar content is called coercion. In a more specific way, implicit type conversion is called coercion and it is known as type conversion. Let's understand this with an example

public class Main {
    public static void main(String[] args) {
        // Declaring character and integer variables
        char alphabet = 'A';
        int ascii_value = alphabet;

        System.out.println("ASCII Value of A is: " + ascii_value);
        // o/p: ASCII Value of A is: 65
    }
}

Here we are initializing the variable "alphabet" which is of type character and assigning the alphabet to a variable "ascii_value" which is of type int. On execution of a program, the character value gets implicitly converted to an integer value by JVM.

Advantages of Polymorphism

  1. It helps the programmer to reuse the codes, i.e., classes once written, tested, and implemented can be reused as required. Saves a lot of time.

  2. A single variable can be used to store multiple data types.

  3. Polymorphism helps in reducing the coupling between different functionalities.


Thanks for reading

I really hope you enjoyed reading it

Follow me: https://www.linkedin.com/in/imazizbohra/