Java Polymorphism – Master the Concept with Real-life Examples!
Polymorphism is another pearl in the ocean of object-oriented programming. It is so necessary that languages that don’t support polymorphism cannot be referred to as Object-Oriented languages.
Languages that support classes but not the mechanism of polymorphism are called object-based languages. Ada is an example of one such language. Java is an object-oriented language, and it supports Polymorphism.
The word Polymorphism can be broken into two words – ‘poly’ means ‘many’ and ‘morph’ means ‘forms’. So, polymorphism means many forms.
Polymorphism is the ability for a data or message to be processed in more than one form. It is a concept by which a single operation can be performed in multiple different ways.
Polymorphism is the concept that allows an object of a class to behave differently in response to a message or action.
Real-Life Examples of Java Polymorphism
A security guard outside an organization behaves differently with different people entering the organization. He acts in a different way when the Boss comes and, in another way when the employees come.
When the customers enter, the guard will respond differently. So here, the behavior of the guard is in various forms, which depends on the member who is coming.
Another example is the sound of animals. We can have a common method sound but with this method, we are using sounds of different animals. The method sound will behave differently with respect to different animals.
Moving forth, we will discuss how polymorphism is implemented in Java and what are the types of polymorphism along with their examples.
What is Java Polymorphism?
We can define polymorphism in the context of Object-Oriented Programming as follows:
The virtue by which the same action can be performed by objects of different classes and each object responds in a different way depending on its class is called Polymorphism.
The following figure illustrates that a single function name can be used to handle the different types and different numbers of arguments. It is quite similar to a particular word having several different meanings depending on the context:
Types of Polymorphism in Java
There are two types of polymorphism in Java:
Let’s discuss each of the types in detail:
1. Static/Compile-Time Polymorphism
When the compiler resolves the polymorphism during the compilation of the program, then we call such polymorphism as compile-time polymorphism or static polymorphism. Sometimes we also call it static binding.
In Java, we can implement or achieve the compile-time/ static polymorphism with the help of Method Overloading.
Let’s see what is Method Overloading:
When a class has two or more than two methods which are having the same name but different types of order or number of parameters, it is known as Method overloading. Java allows a function to have the same name if it can distinguish them by their number and type of arguments.
For example, the following functions are different in Java:
float divide(int a, int b){...}
float divide( float x, float y){...}
float divide (float a,int b) {...}
That is, the function divide() taking two int arguments is different from divide() taking two float arguments, and also from divide() taking both int and float arguments. This is called function overloading.
Let us take an example discussed earlier for finding the minimum numbers of integer types. Suppose we want to find the minimum number of double types. Then, we can use the concept of method overloading.
We will create two or more methods with the same name but different parameters.
Code to illustrate Method/function overloading:
package com.techvidvan.polymorphism; public class MethodOverloadingDemo { public static void main(String[] args) { int intVar1 = 15; int intVar2 = 7; double doubleVar1 = 14.5; double doubleVar2 = 18.3; int result1 = minFunction(intVar1, intVar2); // same function name with different parameters double result2 = minFunction(doubleVar1, doubleVar2); System.out.println("The minimum value of integer types = " + result1); System.out.println("The minimum value of double types = " + result2); } // for integer public static int minFunction(int n1, int n2) { int min; if (n1 > n2) min = n2; else min = n1; return min; } // for double public static double minFunction(double n1, double n2) { double min; if (n1 > n2) min = n2; else min = n1; return min; } }
Output:
The minimum value of double types = 14.5
2. Dynamic/Run-Time Polymorphism
Runtime or dynamic Polymorphism is the polymorphism which resolves dynamically at the runtime rather than compile-time is called. We can also call it as dynamic binding or Dynamic Method Dispatch.
Since the method invocation is during runtime and not during compile-time, this type of polymorphism is called Runtime or dynamic polymorphism.
We can achieve dynamic polymorphism in Java with the help of Method Overriding.
In an object-oriented language, Method overriding occurs when a derived class provides a specific definition of the method that is already present in its parent class. We say that the function in the base class is being overridden.
When we define a method of a base class with the same name and same parameters and with the same return type in the child or derived class, then the method in the subclass overrides the method in the superclass. This process is Method Overriding in Java.
Note: We can not achieve Runtime polymorphism with data members. It can only be achieved through methods.
Code to illustrate Method/function Overriding:
package com.techvidvan.polymorphism; class Shape { void draw() { System.out.println("Drawing Shapes..."); } } class Square extends Shape { //Overriding method of base class with different implementation void draw() { System.out.println("Drawing Square"); } } class Circle extends Shape { //Overriding method of base class with different implementation void draw() { System.out.println("Drawing Circle"); } } class Triangle extends Shape { //Overriding method of base class with different implementation void draw() { System.out.println("Drawing Triangle"); } } public class MethodOverridingDemo { public static void main(String args[]) { //creating object of Base class Shape Shape obj ; obj=new Shape(); obj.draw(); //initiating object with subclasses obj=new Square(); obj.draw(); obj=new Circle(); obj.draw(); obj=new Triangle(); obj.draw(); } }
Output:
Drawing Square
Drawing Circle
Drawing Triangle
Why Java Polymorphism?
With Polymorphism, it is possible to write a method that correctly processes lots of different types of functionalities with the same name. Polymorphism also allows gaining consistency in our code.
For example,
Suppose we need to execute the animalSound() method of both Dog and Cat. To do so, we can create an ‘Animal’ class and extend two subclasses Dog and Cat from it.
In this case, it makes sense to create a method with the same name animalSound() in both these subclasses rather than creating methods with different names.
In our method overloading example, for achieving consistency, we have used the same method name minFunction() to find the minimum of two different types of numbers, that is, int and double types.
The print() method in Java is also an example of method overloading or compile-time polymorphism, which prints the values of different types like int, char, String, double, etc.
Take a deep dive into the concepts of Java Strings with Techvidvan.
Advantages of Java Polymorphism
- Polymorphism allows a superclass to define methods that are common to all of its derived classes while allowing subclasses to specify the additional implementation of some or all of those methods.
- Method Overriding is supported by Dynamic Polymorphism which is a key aspect of dynamic binding or run-time polymorphism.
- Polymorphism provides the ability to a method to do different things on the basis of the object upon which it is acting.
Characteristics of Polymorphism in Java
There are many other characteristics of Polymorphism in Java other than Method Overloading and Method Overriding. They are as follows:
- Coercion
- Operator Overloading
- Polymorphic Variables or Parameters
Let’s discuss these characteristics in detail.
1. Coercion
Coercion in Polymorphism deals with implicit type conversion of one type of object to a new object of a different type. The compiler performs coercion to prevent type errors.
A common example of coercion of string “8” into an integer 8 or double 8.0 or another example is- an integer and string concatenation.
2. Operator Overloading
Operator Overloading is a characteristic of a static polymorphism in which the same operator or symbol behaves differently depending on the input context or the type of operands.
For example, the plus operator + is used for both adding two numbers as well as for concatenating the Strings. Also, operators like ! , & and | are overloaded for logical and bitwise operations. In both cases, only the type of arguments decides the interpretation of the operator.
For a better understanding, it is recommended for you to have a look at Java Operators and its types.
When + operator is used with numbers (integers and floating-point numbers), it performs numeric addition. For example,
int num1 = 5; int num2 = 10; int sum = num1 + num2; // Output = 15
And when we use + operator with strings, it performs concatenation of two Strings. For example,
String firstName = "Tech"; String lastName = "Vidvan"; fullName = firstName + lastName; // Output = TechVidvan
Note: Languages like C++ support the functionality of user-defined operator overloading in which we can define operators to work differently for different operands. But, Java doesn’t support user-defined operator overloading like these languages.
3. Polymorphic Variables or Parameters
In Java, polymorphic variables are represented by the object or instance variables. The reason is that any object variables of a class can have an IS-A relationship for their own classes as well as with subclasses.
Code to understand Polymorphic variables:
package com.techvidvan.polymorphism; class Shape { public void display() { System.out.println("I am a Shape."); } } class Circle extends Shape { @Override public void display() { System.out.println("I am a circle."); } } class PolymorphicVariablesDemo { public static void main(String[] args) { // declaration of object variable obj of the Shape class Shape obj; // object creation of the Shape class obj = new Shape(); obj.display(); // object creation of the Circle class obj = new Circle(); obj.display(); } }
Output:
I am a Circle.
In the above example, we have created an object variable obj of the Shape class. Here, obj is a polymorphic variable. It is because,
- In the statement, obj = new Shape(), obj refers to the object of the Shape class.
- In the statement, obj = new Circle(), obj refers to the object of the Circle class.
Summary
Polymorphism is one of the most essential features of Object-Oriented Programming. Every Java programmer should be well acquainted with this topic to become an expert in Java.
Coming to the end of this article, we understood the importance of using Polymorphism with its advantages. We also discussed its characteristics.
We covered the two types of polymorphism – static or compile-time (method overloading) and dynamic or runtime (method overriding) polymorphism. Both differ with each other in the manner of method binding and method invocation.
We will properly understand the difference between method overloading and method overriding in our upcoming articles.
Thank you for reading our article. Do share our article on Social Media.
Happy Learning 🙂