Polymorphism in Java

Polymorphism in Java is one of the most significant features of Object-Oriented Programming. Through Polymorphism, we can define one interface and use it in multiple ways. Or, to put it in simpler terms, polymorphism allows us to perform the same action in many different ways. 

The derivation of the word Polymorphism is from two different Greek words- poly and morphs. “Poly” means numerous, and “Morphs” means forms. So polymorphism means innumerable forms.

Languages that do not support polymorphism cannot be referred to as Object-Oriented Languages. But instead, they are known as Object Bases Languages. Ada is an example of one such Language. Since Java supports polymorphism, it is an Object-Oriented Language.

Polymorphism occurs when there is inheritance, i.e. there are many classes that are related to each other.

Inheritance is a powerful feature in Java. Inheritance lets one class acquire the properties and attributes of another class. Polymorphism allows us to use these inherited properties to perform different tasks. Thus, allowing us to achieve the same action in many different ways.

Real-Life Examples of Polymorphism to get a better understanding.

An individual can have different relationships with different people. A woman can be a mother, a daughter, a sister, a friend, all at the same time, i.e. she performs other behaviours in different situations.

The human body has different organs. Every organ has a different function to perform; the heart is responsible for blood flow, lungs for breathing, brain for cognitive activity and kidneys for excretion. So we have a standard method function that performs differently depending upon the organ of the body. 

Let’s understand with a coded example:

A superclass named “Shapes” has a method “area()”. Subclasses of “Shapes” can be “Triangle”, “circle”, “Rectangle”, etc. Each subclass has its way of calculating area. Using Inheritance and Polymorphism, the subclasses can use the “area()” method to find the area’s formula for that shape.

class Shapes {
  public void area() {
    System.out.println("The formula for area of ");
  }
}
class Triangle extends Shapes {
  public void area() {
    System.out.println("Triangle is ½ * base * height ");
  }
}
class Circle extends Shapes {
  public void area() {
    System.out.println("Circle is 3.14 * radius * radius ");
  }
}
class Main {
  public static void main(String[] args) {
    Shapes myShape = new Shapes();  // Create a Shapes object
    Shapes myTriangle = new Triangle();  // Create a Triangle object
    Shapes myCircle = new Circle();  // Create a Circle object
    myShape.area();
    myTriangle.area();
    myShape.area();
    myCircle.area();
  }
}

Output:

The formula for area of Triangle is ½ * base * height
The formula for area of Circle is 3.14 * radius * radius

Types of Polymorphism

In Java, polymorphism can be performed by two different methods:

  1. Method Overloading
  2. Method Overriding

Based on this, polymorphism can be classified into two types:

  1. Static / Compile-Time Polymorphism
  2. Dynamic / Runtime Polymorphism

Static / Compile-Time Polymorphism

Compile-Time polymorphism is also known as Static Polymorphism. In this process, the call to the method is resolved at compile-time. Compile-Time polymorphism is achieved through Method Overloading. This type of polymorphism can also be achieved through Operator Overloading. However, Java does not support Operator Overloading.

Method Overloading is when a class has multiple methods with the same name, but the number, types and order of parameters and the return type of the methods are different. Java allows the user freedom to use the same name for various functions as long as it can distinguish between them by the type and number of parameters. 

Example of Method Overloading

class Shapes {
  public void area() {
    System.out.println("Find area ");
  }
public void area(int r) {
    System.out.println("Circle area = "+3.14*r*r);
  }

public void area(double b, double h) {
    System.out.println("Triangle area="+0.5*b*h);
  }
public void area(int l, int b) {
    System.out.println("Rectangle area="+l*b);
  }


}

class Main {
  public static void main(String[] args) {
    Shapes myShape = new Shapes();  // Create a Shapes object
    
    myShape.area();
    myShape.area(5);
    myShape.area(6.0,1.2);
    myShape.area(6,2);
    
  }
}

Output:

Find area
Circle area = 78.5
Triangle area=3.60
Rectangle area=12

Dynamic / Runtime Polymorphism

Runtime polymorphism is also known as Dynamic Binding or Dynamic Method Dispatch. In this process, the call to an overridden method is resolved dynamically at runtime rather than at compile-time. Runtime polymorphism is achieved through Method Overriding.

Method Overriding is done when a child or a subclass has a method with the same name, parameters and return type as the parent or the superclass, then that function overrides the function in the superclass. In simpler terms, if the subclass provides its definition to a method already present in the superclass, then that function in the base class is said to be overridden.

It should be noted that runtime polymorphism can only be achieved through functions and not data members. 

Overriding is done by using a reference variable of the superclass. Which method to be called is determined based on the object which is being referred to by the reference variable. This is also known as Upcasting.

Upcasting is done when the Parent class’s reference variable refers to the object of the child class. For example:

class A{} 
class B extends A{}  
A a=new B(); //upcasting

Examples of Runtime Polymorphism

Example 1:

In this example, we are creating one superclass Animal and three subclasses, Herbivores, Carnivores and Omnivores. Subclasses extend the superclass and override its eat() method. We will call the eat() method by the reference variable of  Parent class, i.e. Animal class. As it refers to the base class object and the base class method overrides the superclass method, the base class method is invoked at runtime. As Java Virtual Machine or the JVM and not the compiler determines method invocation, it is runtime polymorphism.

class Animal{  
  void eat(){
System.out.println("Animals Eat");
}  
}  
class herbivores extends Animal{  
  void eat(){
System.out.println("Herbivores Eat Plants");
} 
  }
class omnivores extends Animal{  
  void eat(){
System.out.println("Omnivores Eat Plants and meat");
} 
  }
class carnivores extends Animal{  
  void eat(){
System.out.println("Carnivores Eat meat");
} 
  }
class main{
  public static void main(String args[]){ 
    Animal A = new Animal();
    Animal h = new herbivores(); //upcasting  
	Animal o = new omnivores(); //upcasting  
    Animal c = new carnivores(); //upcasting  
    A.eat();
    h.eat();
    o.eat();  
    c.eat();  
  
  }  
}  

Output:

Animals eat
Herbivores Eat Plants
Omnivores Eat Plants and meat
Carnivores Eat meat

Example 2:

In this example, we are creating one superclass Hillstations and three subclasses Manali, Mussoorie, Gulmarg. Subclasses extend the superclass and override its location() and famousfor() method. We will call the location() and famousfor() method by the Parent class’, i.e. Hillstations class. As it refers to the base class object and the base class method overrides the superclass method, the base class method is invoked at runtime. As Java Virtual Machine or the JVM and not the compiler determines method invocation, it is runtime polymorphism.

class Hillstations{  
  void location(){
System.out.println("Location is:");
}  
void famousfor(){
System.out.println("Famous for:");
}  

}  
class Manali extends Hillstations {  
  void location(){
System.out.println("Manali is in Himachal Pradesh");
}  
void famousfor(){
System.out.println("It is Famous for Hadimba Temple and adventure sports");
}  
  }
class Mussoorie extends Hillstations {  
  void location(){
System.out.println("Mussoorie is in Uttarakhand");
}  
void famousfor(){
System.out.println("It is Famous for education institutions");
}  
  }
class Gulmarg extends Hillstations {  
  void location(){
System.out.println("Gulmarg is in J&K");
}  
void famousfor(){
System.out.println("It is Famous for skiing");
}  
  }
class main{
  public static void main(String args[]){ 
    Hillstations A = new Hillstations();
    Hillstations M = new Manali();

    Hillstations Mu = new Mussoorie();

    Hillstations G = new Gulmarg();

    A.location();
A.famousfor();

M.location();
M.famousfor();

Mu.location();
Mu.famousfor();

G.location();
G.famousfor();
  }  
}  

Output:

Location is:
Famous for:
Manali is in Himachal Pradesh
It is Famous for Hadimba Temple and adventure sports
Mussoorie is in Uttarakhand
It is Famous for education institutions
Gulmarg is in J&K
It is Famous for skiing

Why use Polymorphism?

Polymorphism makes it possible to write a method that can correctly process lots of different types of functionalities that have the same name. We can also gain consistency in our code by using polymorphism.

Polymorphism has a lot of advantages:

  1. It provides reusability to the code. The classes that are written, tested and implemented can be reused multiple times. This, in turn, saves a lot of time for the coder. Also, the code can be changed without affecting the original code.
  2. A single variable can be used to store multiple data values. The value of a variable inherited from the superclass into the subclass can be changed without changing that variable’s value in the superclass or any other subclasses.
  3. With lesser lines of code, it becomes easier for the programmer to debug the code.

Additional Characteristics of Polymorphism

Polymorphism has many other characteristics other than Method Overloading and Method Overriding. They include:

  • Coercion
  • Internal Operator Overloading
  • Polymorphic Variables or Parameters

1. Coercion

Coercion deals with implicitly converting one type of object into a new object of a different kind. This is done automatically to prevent type errors in the code. 

Example :

class coercion {

  public static void main(String[] args) {
    Double area = 3.14*5*7;
System.out.println(area);
String s = "happy";
int x=5;
String word = s+x;
System.out.println(word);

  }
}

Output:

109.9
happy5


2. Internal Operator Overloading

In Operator Overloading, an operator or symbol behaves in more ways than one depending upon the input context or the type of operands. It is a characteristic of static polymorphism. Although Java does not support user-defined operator overloading like C++, where the user can define how an operator works for different operands, there are few instances where Java internally overloads operators.

In the case of +, it can be used for addition and also for concatenation.

For example:

class coercion {

  public static void main(String[] args) {
    
String s = "happy";
String s1 = "world";
int x=5;
int y=10;

System.out.println(s+s1);
System.out.println(x+y);

  }
}

Output :

happyworld
15

Similarly, operators like !, &, and | are also overloaded for logical and bitwise operations. In both of these cases, the type of arguments decides how the operator is interpreted.

 3. Polymorphic Variables or Parameters

In Java, the object or instance variables represent the polymorphic variables. This is because any object variables of a class can have an IS-A relationship with their own classes and subclasses.

For example:

class Shape
{
public void display()
{
System.out.println("A Shape.");
}
}
class Triangle extends Shape
{
public void display()
{
System.out.println("I am a triangle.");
}
}
class Main{
public static void main(String[] args)
{
Shape obj;
obj = new Shape();
obj.display();
obj = new Triangle();
obj.display();
}
}

Output:

A Shape.
I am a triangle.

Here, the obj object is a polymorphic variable. This is because the superclass’s same object refers to the parent class (Shape) and the child class (Triangle). 

This brings us to the end of the blog on Exception Handling in Java. Hope this helps you to up-skill your Java skills. To learn more about programming and other related concepts, check out the courses on Great Learning Academy

Also, if you are preparing for Interviews, check out these Interview Questions for Java to ace it like a pro.

1

LEAVE A REPLY

Please enter your comment!
Please enter your name here

12 − five =