Polymorphism in Java


JavaViews 2853

Polymorphism in Java is another important feature of OOPs concept. We have seen an overview of polymorphism in the tutorial OOPs concepts in Java. In this tutorial, we will understand in detail about polymorphism and its different types. We will cover about Static Polymorphism, Dynamic Polymorphism, Runtime Polymorphism.

What is polymorphism in Java

Polymorphism in Java as the name suggests means the ability to take multiple forms. It is derived from the Greek words where Poly means many and morph means forms. In Java, polymorphism in java is that the same method can be implemented in different ways. To understand this, we need to have an idea of inheritance in java as well which we have learned in the previous tutorial.

Types of Polymorphism in Java

Below are the different types of polymorphism in java.

Polymorphism in Java

Static Polymorphism

When we overload a static method, we call it as static polymorphism. Since it resolves the polymorphism during compile time, we can call also name it as compile-time polymorphism. We can implement this type of polymorphism in java using either method overloading or operator overloading. In static polymorphism, during compile time it identifies which method to call based on the parameters we pass.

Let’s understand this in detail with the help of examples.

Method overloading

When there are many methods with the same name but different implementations, we call it a method overloading. We can implement method overloading in two different ways:

  • Different number of parameters
  • Different types of parameters.

First, let’s look at an example of method overloading with a different number of parameters. In this example, we have created a class Area that has 2 methods computeArea(int) and computeArea(int, int). The difference in both the method is one has 1 parameter and the other has 2 parameters even though the method name is the same. So when we call the method using 1 parameter, it calls computeArea(int) and when we call the method with 2 parameters, it calls computeArea(int, int).

Method overloading

class Area {
  
  public void computeArea(int a) {
    int area = a *a;
    System.out.println("Area of square: " + area);
  }
   public void computeArea(int a, int b) {
     int area = a*b;
     System.out.println("Area of rectangle: "  + area);
   }
}
public class CalculateArea {

  public static void main(String[] args) {
    Area ar = new Area();
    ar.computeArea(5);
    ar.computeArea(4, 2);

  }

}
Area of square: 25
Area of rectangle: 8

Below is an example of method overloading where the same method can have different types of parameters. In the below code, we have a method subtract with 2 different types of parameters. One has parameters of type int and the other of type double. Now, when we call the method using the class object, based on the type of data, it calls the corresponding method. Hence, the first method calls subtract(int, int) since we are passing integer numbers. The second method calls subtract(double, double) since we are passing double numbers.

Method Overloading

class Difference {
  public void subtract(int a, int b) {
    int diff = a - b;
    System.out.println("Difference: " + diff);
  }
  public void subtract(double a, double b) {
    double diff = a - b;
    System.out.println("Difference: " + diff);
  }
}
public class MethodOverloadingDemo {

  public static void main(String[] args) {
    Difference d = new Difference();
    d.subtract(10, 5);
    d.subtract(5.51, 2.21);
  }

}
Difference: 5
Difference: 3.3

Operator overloading

Similar to method overloading, we can also override an operator which is also an example of static polymorphism in java. But we can overload only the “+” operator in Java and do not support the overloading of other operators. When we use String as operands between + it results in String concatenation. When we use numbers as operands between + it results in the addition of two numbers. Below is an example of + operator overloading.

class Operatordemo {
  public void operator(String s1, String s2) {
    String s = s1+s2;
    System.out.println("String concatenation: " + s);
  }
  
  public void operator(int x, int y) {
    int sum = x + y;
    System.out.println("Sum: "+ sum);
  }
}
public class OperatorOverloading {

  public static void main(String[] args) {
    Operatordemo o = new Operatordemo();
    o.operator("Good", "Evening");
    o.operator(4, 9);

  }

}
String concatenation: GoodEvening
Sum: 13

Dynamic Polymorphism

When polymorphism resolves during runtime, we call it dynamic or runtime polymorphism. In this type of polymorphism in java, it uses the reference variable of the superclass to call the overridden method. This means, based on the object that is referred by the reference variable, it calls the overridden method of that corresponding class. We can use the method overriding concept to implement Dynamic polymorphism.

Method overriding

When the subclass has the same method of the base class, we call it a method overriding which means that the subclass has overridden the base class method. Based on the type of object we create, it calls the method of that corresponding class. This means, if we create an object of the superclass and refer it using the subclass, then it calls the method of the subclass. Since it computes this during runtime, we call it as runtime polymorphism in java.

You will be able to understand this concept clearly with the below example. We have created a parent class Vehicle and 2 subclasses Bike and Car. The parent class has a method speed and both the subclasses have overridden the base class method speed.

If we create an object of instance Vehicle class and call the speed method (v.speed) it calls the parent class method. When we call the speed method using object created of instance Bike class(b.speed), it calls the Bike class method. Similarly, when we call the method using the object created of instance Car class(c.speed), it calls the Car class method.

Polymorphism in Java

class Vehicle {
  public void speed() {
    System.out.println("Default speed");
  }
}

class Bike extends Vehicle {
  public void speed() {
    System.out.println("Bike speed");
  }
}

class Car extends Vehicle {
  public void speed() {
    System.out.println("Car speed");
  }
}
public class VehicleType {

  public static void main(String[] args) {
    //Create an instance of Vehicle
    Vehicle v = new Vehicle();
    v.speed();
    
    //Create an instance of Bike
    Vehicle b = new Bike();
    b.speed();
    
    //Create an instance of Car
    Vehicle c = new Car();
    c.speed();

  }

}
Default speed
Bike speed
Car speed

Below is another example of runtime polymorphism where we can use the same object name to create multiple class instances. We first declare an object of class Fruits. Then using the new keyword we instantiate the object variable for the class Fruits. When we use this object to call the taste method, it calls the taste method of Fruits class. Next, when we instantiate the object variable for the class Apple and call the taste method using this object, it calls the method of Apple class. Similarly, it happens for the Pineapple class.

class Fruits {
  public void taste() {
    System.out.println("Fruits taste");
  }
}

class Apple extends Fruits {
  public void taste() {
    System.out.println("Sweet taste");
  }
}

class Pineapple extends Fruits {
  public void taste() {
    System.out.println("Sour taste");
  }
}

public class FruitsDemo {

  public static void main(String[] args) {
    Fruits f;
    f = new Fruits();
    f.taste();
    f = new Apple();
    f.taste();
    f = new Pineapple();
    f.taste();
  }

}
Fruits taste
Sweet taste
Sour taste

Let’s consider another example below where we call the method of a subclass which does not have an overridden method. In such a case, it calls the parents class method. AnimalDemo class does not have the method animaltype. Hence it calls method of Cow class since AnimalDemo class extends the Cow class.

class Animal {
  public void animaltype() {
    System.out.println("Animal");
  }
}

class Cow extends Animal {
  public void animaltype() {
    System.out.println("Herbivorous");
  }
}

public class AnimalDemo extends Cow{

  public static void main(String[] args) {
    Animal a;
    a = new AnimalDemo();
    a.animaltype();

  }

}
Herbivorous

Runtime polymorphism with data member

In runtime polymorphism, only the method is overridden and not the data member or variable. From the below example, we can clearly understand this difference. When we create an object of instance SBI class from the Bank class, it calls the superclass variable since data members are not overridden. In order to access the subclass variable, we need to create the object from the subclass i.e SBI s = new SBI().

class Bank {
  public double interestRate = 7.5;
}

class SBI extends Bank {
  public double interestRate = 6.4;
}
public class BankDemo {

  public static void main(String[] args) {
    Bank b = new SBI();
    System.out.println(b.interestRate);
    SBI s = new SBI();
    System.out.println(s.interestRate);
  }

}
7.5
6.4

Difference between Method overloading and Method overriding

Method overloadingMethod overriding
This implements static polymorphismThis implements dynamic polymorphism
This happens during compile timeThis happens during runtime
Same methods are present in the same classSame methods are present in different classes

Reference

Translate »