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.
Table of Contents
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.
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).
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.
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.
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 f 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 b 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 overloading | Method overriding |
---|---|
This implements static polymorphism | This implements dynamic polymorphism |
This happens during compile time | This happens during runtime |
Same methods are present in the same class | Same methods are present in different classes |