Polymorphism Program in Java
Polymorphism Program in Java: Polymorphism means the existence of different forms of an object. The object can be a class object or a real-time entity. For example, a person can be a son, an employee, a husband, or an uncle at the same time. Thus, the characteristics of a person are dependent on the scenario. The word polymorphism is made up of two Greek words: one is poly, and another is morphs. The meaning of the word poly is “many”, and the meaning of the word morphs is “form”. The polymorphism program in Java illustrates how polymorphism is achieved in Java programming.
Types of Polymorphism
Following are the two types of polymorphism that exist in Java.
1) Compile-time polymorphism
2) Run-time polymorphism
Let’s discuss each type of polymorphism in detail.
Compile-time polymorphism
Compile-time polymorphism is also called static polymorphism. In order to achieve compile-time polymorphism, operator overloading or method overloading is done in the programming. Since operator overloading is not supported by Java, the only thing left to do to achieve static polymorphism is method overloading. In compile-time polymorphism, it is the Java compiler that takes the decision of calling the methods.
Method overloading in Java
To achieve method overloading, methods in Java must have different signatures but the same name. The signature of a method includes the method name, its parameters. Note that the return type or access specifier of a method is never included in the signature. Since the name of the method has to be the same in method overloading, at least one of the following conditions must hold true to achieve method overloading.
1) Number of parameters of methods must be different
2) Types of parameters of methods must be different
3) Order of parameters of methods must be different
The following Java program demonstrates all the above three conditions to achieve method overloading.
FileName: MethodOverloadingExample.Java
// A class that overloads the method sum() class NumberSum { // first method // contains two integer parameters int sum(int a, int b) { int total = a + b; return total; } // second method // contains three integer parameters int sum(int a, int b, int c) { int total = a + b + c; return total; } // third method // contains two parameters // one is of float type and another is of integer type float sum(float a, int b) { float total = a + b; return total; } // fourth method // contains two character parameters int sum(char a, char b) { // ASCII values of the characters a and b is added int total = a + b; return total; } // fifth method // contains two parameters // one is of integer type and another is of float type float sum(int a, float b) { float total = a + b; return total; } } public class MethodOverloadingExample { // driver method public static void main(String argvs[]) { // creating an object of the class NumberSum NumberSum obj = new NumberSum(); int result; // for storing the outcome returned by the methods result = obj.sum(9, 7); // invoking the first method System.out.println("Result given by the first method is: " + result); result = obj.sum(9, 5, 7); // invoking the second method System.out.println("Result given by the second method is: " + result); float res; res = obj.sum(8.7f, 7); // invoking the third method System.out.println("Result given by the third method is: " + res); result = obj.sum('a', 'b'); // invoking the fourth method // ASCII value of 'a' is 97 and 'b' is 98. So, 97 + 98 = 195 System.out.println("Result given by the fourth method is: " + result); res = obj.sum(6, 7.7f); // invoking the fifth method System.out.println("Result given by the fifth method is: " + res); } }
Output:
Result given by the first method is: 16 Result given by the second method is: 21 Result given by the third method is: 15.7 Result given by the fourth method is: 195 Result given by the fifth method is: 13.7
Explanation: The above program overloads the method sum() by including all three conditions. Look at the first and the second sum() methods. The first sum() method contains two integer parameters, whereas the second sum() method contains the three integer parameters resulting in a difference in parameters. The Java compiler distinguishes the first two methods on the basis of the number of parameters. Similarly, the first and third methods have the same number of parameters, but the type of parameters is different. Therefore, the type of parameters severs the basis of difference to distinguish between these the first and the third sum() methods. If we consider the third and the fifth sum() methods, we see that number of parameters are the same, but the order of parameters is different. The first parameter of the third sum() method is int and the second parameter is float, whereas the first parameter of the fifth sum() method is float, and the second parameter is int, resulting in the difference in the order of the parameters.
Thus, we see there all the five sum() methods have different signatures. When the invocation of the sum() methods is done in the driver method, the Java compiler can differentiate these methods on the basis of signatures resulting in static polymorphism.
Run-time polymorphism
Run-time polymorphism is also called dynamic polymorphism. In dynamic polymorphism, the decision of invoking a method is decided during run-time, i.e., after the compilation process is done. In Java, dynamic polymorphism can only be achieved if method overriding is done. Also, method overriding is only possible when inheritance is done in the program. Therefore, we can say without inheritance; dynamic polymorphism is not possible. In run-time polymorphism, the reference variable of a parent class holds the object of the child class (also known as upcasting). Now, observe the code of dynamic polymorphism.
// Parent class class BankInterest { void rateOfInterest() { System.out.println("Rate of interest of a bank is 5.5% "); } } // child class overriding the method rateOfInterest() class HDFCBankInterest extends BankInterest { @Override void rateOfInterest() { System.out.println("Rate of interest of HDFC bank is 6.5% "); } } // child class overriding the method rateOfInterest() class ICICIBankInterest extends BankInterest { @Override void rateOfInterest() { System.out.println("Rate of interest of ICICI bank is 8% "); } } public class DynamicPolymorphismExample { public static void main(String argvs[]) { // reference variable obj1 is holding // the object of class HDFCBankInterest BankInterest obj1 = new HDFCBankInterest(); // upcasting // reference variable obj2 is holding // the object of class ICICIBankInterest BankInterest obj2 = new ICICIBankInterest(); // upcasting // invoking the method rateOfInterest() of the class HDFCBankInterest obj1.rateOfInterest(); // invoking the method rateOfInterest() of the class ICICIBankInterest obj2.rateOfInterest(); } }
Output:
Rate of interest of HDFC bank is 6.5%
Rate of interest of ICICI bank is 8%
Explanation: The reference variables, obj1 and obj2, are of types of the parent class BankInterest. Therefore, during compile-time, when the compiler watches the statements obj1.rateOfInterest(); and obj2.rateOfInterest(); it checks whether the method rateOfInterest(); is present in the parent class or not. If the method is not present, the compilation error is generated. Since the method is present, the compilation process is completed without any hiccup.
During run-time, it is evaluated that obj1 is holding the object of the child class HDFCBankInterest. Therefore, the statement obj1.rateOfInterest(); invokes the rateOfInterest(); method of the class HDFCBankInterest. Similarly, the statement obj2.rateOfInterest(); invokes the rateOfInterest(); method of the class ICICIBankInterest. Thus, we see whatever impression we get during the compile-time is not the same during the run-time.