GFG Day 11: Polymorphism

sri parthusri parthu
9 min read

Polymorphism in Java

  • Polymorphism means "many forms." It allows objects to take many forms, especially methods behaving differently depending on the object that’s calling them.

Types of Polymorphism in Java

Types of Polymorphism in Java

TypeAlso CalledAchieved ByTiming
β†’ Compile-Time PolymorphismStatic PolymorphismMethod OverloadingDuring Compilation
β†’ Runtime PolymorphismDynamic PolymorphismMethod OverridingAt Runtime

poly

1. Compile-Time Polymorphism

  • Compile-Time In Java, polymorphism is sometimes referred to as method overloading or static polymorphism. This happens when multiple methods with the same name but different parameters are found in the same class.

Java Polymorphism

Method Overloading

  • Method overloading in Java refers to the situation where several functions with the same name but different parameters are overloaded, as we covered before. Changes in the quantity or type of arguments might overload functions.

Example of Method overloading by changing the number of arguments

// Method overloading By using
// Different Types of Arguments

// Class 1
// Helper class
class Helper {

    // Method with 2 integer parameters
    public static int Multiply(int a, int b)
    {
        // Returns product of integer numbers
        return a * b;
    }

    // Method 2
    // With same name but with 2 double parameters
    public static double Multiply(double a, double b)
    {
        // Returns product of double numbers
        return a * b;
    }
}

// Class 2
// Main class
public class Main
{
    // Main driver method
    public static void main(String[] args) {

        // Calling method by passing
        // input as in arguments
        System.out.println(Helper.Multiply(2, 4));
        System.out.println(Helper.Multiply(5.5, 6.3));
    }
}

Output

8
34.65

Explanation: The Multiply method is overloaded with different kinds of parameters. Based on the arguments, the compiler selects the appropriate method at compile time.

Real-Life Illustration of Polymorphism

  • Consider a person who plays different roles in life, like a father, a husband, and an employee. Each of these roles defines different behaviors of the person depending on the object calling it.

Example of different Roles of a Person

// Parent class Person
class Person {

    // Method that displays the 
    // role of a person
    public void role() {
        System.out.println("I am a person.");
    }
}

// Child class Father that 
// overrides the role method
class Father extends Person {

    // Overridden method to show 
    // Outputthe role of a father
    @Override
    public void role() {
        System.out.println("I am a father.");
    }
}

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

        // Creating a reference of type Person 
        // but initializing it with Father class object
        Person p = new Father();

        // Calling the role method. It calls the 
        // overridden version in Father class
        p.role();  
    }
}

Output

I am a father.

Explanation: A general message is printed by the role() function of the Person class in the example above. Role() is overridden by the Father class to print a particular message. In order to show polymorphism at runtime, an object of type Father is pointed to using the reference of type Person. Role() calls Father's override method.

Why Use Polymorphism in Java?

  • Using polymorphism in Java has many benefits, which are listed below:

    • Reusability of code

    • Flexibility to write cleaner, extensible code

    • Ability to call derived class methods using base class references

    • Promotes loose coupling

2. Runtime Polymorphism

  • Java features a runtime polymorphism called Dynamic Method Dispatch. Runtime resolves a function call to the overridden method in this process. Method Overriding is the process that produces this kind of polymorphism. However, when a derived class has a definition for one of the base class's member functions, this is known as method overriding. It is said to override that base function.

Method Overriding

  • Method overriding in Java means when a subclass provides a specific implementation of a method that is already defined in its superclass. The method in the subclass must have the same name, return type, and parameters as the method in the superclass. Method overriding allows a subclass to modify or extend the behavior of an existing method in the parent class. This enables dynamic method dispatch, where the method that gets executed is determined at runtime based on the object's actual type.

Example of demonstrates method overriding in Java, where the Print() method is redefined in the subclasses (subclass1 and subclass2) to provide specific implementations.

// Java Program for Method Overriding

// Class 1
// Helper class
class Parent {

    // Method of parent class
    public void Print() {
        System.out.println("parent class");
    }
}

// Class 2
// Helper class
class subclass1 extends Parent {

    // Method
    public void Print() { 
      System.out.println("subclass1"); 
    }
}

// Class 3
// Helper class
class subclass2 extends Parent {

    // Method
    public void Print() {
        System.out.println("subclass2");
    }
}

// Class 4
// Main class
public class Main {

    // Main driver method
    public static void main(String[] args) {

        // Creating object of class 1
        Parent a;

        // Now we will be calling print methods
        // inside main() method
        a = new subclass1();
        a.Print();

        a = new subclass2();
        a.Print();
    }
}

Output

subclass1
subclass2

Explanation: In the example above, the method inside the child class is called when an object of the child class is created. The reason for this is that the child class overrides the parent class's method. For the child class, this method is more important than the parent method. The body is thus executed within the child class.

Advantages of Polymorphism

  • Encourages code reuse.

  • Simplifies maintenance.

  • Enables dynamic method dispatch.

  • Helps in writing generic code that works with many types.

Disadvantages of Polymorphism

  • It can make more difficult to understand the behavior of an object.

  • This may cause performance issues, as polymorphic behavior may require additional computations at runtime.


Dynamic Method Dispatch or Runtime Polymorphism in Java

  • One of Java's methods for enabling Runtime Polymorphism is method overriding. A call to an overridden method is resolved at runtime instead of compile time via a technique called dynamic method dispatch.

    • Java uses the type of the object being referenced to at the time of the call to determine which version (superclass/subclass) of an overridden method should be executed when the method is called through a superclass reference. Consequently, this decision is determined at runtime.

    • At run-time, the version of an overridden method that is executed depends on the type of the object being referenced, not the type of the reference variable.

    • An object of a subclass may be referenced via a superclass reference variable. Upcasting is another name for this. Java makes use of this feature to resolve runtime calls to overridden methods.

Blank Diagram - Page 1 (4)

Consequently, when different kinds of objects are referenced to through a superclass reference variable, multiple versions of the method are run if a superclass has a method that is overridden by a subclass. Dynamic method dispatch is demonstrated in the following example:

class A
{
    void m1()
    {
        System.out.println("Inside A's m1 method");
    }
}

class B extends A
{
    // overriding m1()
    void m1()
    {
        System.out.println("Inside B's m1 method");
    }
}

class C extends A
{
    // overriding m1()
    void m1()
    {
        System.out.println("Inside C's m1 method");
    }
}

// Driver class
class Dispatch
{
    public static void main(String args[])
    {
        // object of type A
        A a = new A();

        // object of type B
        B b = new B();

        // object of type C
        C c = new C();

        // obtain a reference of type A
        A ref;

        // ref refers to an A object
        ref = a;

        // calling A's version of m1()
        ref.m1();

        // now ref refers to a B object
        ref = b;

        // calling B's version of m1()
        ref.m1();

        // now ref refers to a C object
        ref = c;

        // calling C's version of m1()
        ref.m1();
    }
}

Output

Inside A's m1 method
Inside B's m1 method
Inside C's m1 method

Explanation:

The above example creates one superclass called A and its two subclasses, B and C. These subclasses override the m1() method.

  • Inside the main() method in the Dispatch class, initially objects of type A, B, and C are declared.
A a = new A(); // object of type A
B b = new B(); // object of type B
C c = new C(); // object of type C

Blank Diagram - Page 1 (1)

  • Now a reference of type A, called ref, is also declared, initially it will point to null.

      A ref; // obtain a reference of type A
    

    w

  • Now we are assigning a reference to each type of object (either A's or B's or C's) to ref, one-by-one, and uses that reference to invoke m1( ). As the output shows, the version of m1( ) executed is determined by the type of object being referred to at the time of the call.

      ref = a; // r refers to an A object
      ref.m1(); // calling A's version of m1()
    

    q

      ref = b; // now r refers to a B object
      ref.m1(); // calling B's version of m1()
    

    q

      ref = c; // now r refers to a C object
      ref.m1(); // calling C's version of m1()
    

    Blank Diagram - Page 1 (3)

    Runtime Polymorphism with Data Members

    • In Java, we can override methods only, not the variables(data members), so runtime polymorphism cannot be achieved by data members.

For example :

    // class A
    class A
    {
        int x = 10;
    }

    // class B
    class B extends A
    {
        int x = 20;
    }

    // Driver class
    public class Test
    {
        public static void main(String args[])
        {
            A a = new B(); // object of type B

            // Data member of class A will be accessed
            System.out.println(a.x);
        }
    }

Explanation :

  • 'x' is a variable shared by class A (super class) and class B (sub class) in the program shown above. Using 'a', which is of type A, we now create an object of class B. Because variables cannot be overridden, the statement "a.x" will always refer to a member of the super class.

Advantages of Dynamic Method Dispatch

  1. Dynamic method dispatch allow Java to support overriding of methods which is central for run-time polymorphism.

  2. It allows a class to specify methods that will be common to all of its derivatives, while allowing subclasses to define the specific implementation of some or all of those methods.

  3. It also allow subclasses to add its specific methods subclasses to define the specific implementation of some.

Static vs Dynamic binding

  • Static binding is done during compile-time while dynamic binding is done during run-time.

  • private, final and static methods and variables uses static binding and bonded by compiler while overridden methods are bonded during runtime based upon type of runtime object


Happy Learning

Thanks For Reading! :)

SriParthu πŸ’πŸ’₯

0
Subscribe to my newsletter

Read articles from sri parthu directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

sri parthu
sri parthu

Hello! I'm Sri Parthu! 🌟 I'm aiming to be a DevOps & Cloud enthusiast πŸš€ Currently, I'm studying for a BA at Dr. Ambedkar Open University πŸ“š I really love changing how IT works to make it better πŸ’‘ Let's connect and learn together! πŸŒˆπŸ‘‹