Polymorphism in Java
“polymorphism” means ‘a state of having many shapes’ or ‘the capacity to take on different forms’. In Java, Polymorphism is an ability to access objects of related classes through a single, uniform interface. Two types of polymorphism in Java,
- Compile time polymorphism (static binding)
- Run-time polymorphism (dynamic binding).
Method overloading is an example of static polymorphism, while method overriding is an example of dynamic polymorphism. Method overloading decides the method to be called in compile time. Method overloading is compile time polymorphism. Refer method overloading to understand the compile time polymorphism.
Next type is Runtime polymorphism. Runtime polymorphism applicable in inheritance relationship in java. In inheritance, the parent class reference can point the subclass objects. Reference variable is type of parent class and the actual object would be type of subclass. when we try to invoke the method using parent class reference variable, it would invoke the method of actual object. It is referred as runtime polymorphism in java.
Polymorphism is the capability of a method to do different things based on the object that it is acting upon.
Let us take an example,
abstract class Animal { public abstract void eat();} // Parent class
class Cow extends Animal { public void eat(){……} } // child1 implements eat()
class Dog extends Animal { public void eat(){……} } // child2 implements eat()
class Tiger extends Animal { public void eat(){……} } // child3 implements eat()
Animal animal; // animal is reference variable.
animal = new Cow(); // animal reference variable refer Cow object. (parent reference variable refer child object)
animal.eat(); // animal IS-A Animal and animal IS-A Cat. Actual object is Cat. would call Cat.eat()
animal = new Dog(); // animal reference variable refer Dog object. (parent reference variable refer child object)
animal.eat(); // animal IS-A Animal and animal IS-A Dog. Actual object is Dog. would call Dog.eat()
The Java virtual machine (JVM) calls the appropriate method for the object that is referred to in each variable. The same method “animal.eat” would invoke multiple implementations “Cat.eat” or “Dog.eat” or “Tiger.eat” based on the object referred by reference variable. In other words, polymorphism allows you define one high level interface (Animal) and access multiple implementations (Cow,Dog,Tiger).
High Level Abstraction :
Now we are clear about theory of polymorphism and how to implement polymorphism in java. Let us discuss on how to use polymorphism effectively in design. Polymorphism help to achieve abstraction in implementation. We can just expose the parent classes to external world and hide the internal child classes implementation by polymorphism.
//Let us assume info.building.beans package implemented and packaged as a library “building.jar”
package info.building.beans; // Implemented by programmer1 Mike
class Building {
int height;
int width;
public static Building getInstance(int h, int w, int totalBlocks, String type ) throws Exception {
if(type.equalsIgnoreCase(“Commercial”)) {
return new CommericalBuilding(h,w,totalBlocks);
}else if(type.equalsIgnoreCase(“Residence”)) {
return new ResidenticalBuilding(h, w, totalBlocks);
}
throw new Exception(“it is not a valid type:” + type);
}
public void display() {
System.out.println(“Height:” + height + “,Width:” + width );
}
}
class CommericalBuilding extends Building{
int numberOfShops;
public CommericalBuilding(int h, int w, int no) {
this.height = h;
this.width = w;
this.numberOfShops = no;
}
@Override
public void display() {
System.out.println(“Height:” + height + “,Width:” + width+ “, number of shops:”+ numberOfShops);
}
}
class ResidenticalBuilding extends Building {
int numberOfHouses;
public ResidenticalBuilding(int h, int w, int no) {
this.height = h;
this.width = w;
this.numberOfHouses = no;
}
@Override
public void display() {
System.out.println(“Height:” + height + “,Width:” + width + ” number of houses:”+ numberOfHouses);
}
}
class TaxCalculator{
/* Now we have to expose a method to calculate tax on building based on logic of
* a). Commercial building, each shop would be taxed 1000;
* b). Residence building, each home would be taxed 50; */
public static Integer calculate(Building building) {
if(building instanceof CommericalBuilding ) {
return ( (CommericalBuilding) building).numberOfShops * 1000;
}else if(building instanceof ResidenticalBuilding) {
return ( (ResidenticalBuilding) building).numberOfHouses * 50;
}
return -1;
}
}
// This is implemented by programmer 2 Peter and use the above jar “library.jar”
package info.javaarch; // Implemented by programmer2 Peter
//This is third party component access “building.jar” and access the objects as below,
public class AbstractionByPolymorphism{
public static void main(String arg[]) throws Exception {
Building officeBuilding = Building.getInstance(100, 200, 25, “Commercial”);
Building homeBuilding = Building.getInstance(1000, 120, 75, “Residence”);
officeBuilding.display(); // displays Height:100,Width:200, number of shops:25 by calling CommericalBuilding.display()
homeBuilding.display(); // displays Height:1000,Width:120 number of houses:75 by calling ResidenticalBuilding.display()
System.out.println(“Tax on office building:” + TaxCalculator.calculate(officeBuilding)); //returns 25000
System.out.println(“Tax on home building:” + TaxCalculator.calculate(homeBuilding)); // returns 3750
}
}
Let us say that “info.javaarch.AbstractionByPolymorphism” is implemented by Peter and “info.building.beans” implemented by Mike. Peter is unaware of subclasses implementation and internal implementation taxcalculator. But still he is able get benefit out of all the subclasses by parent reference variable. Polymorphism would be great tool in object oriented programming to achieve high level abstraction. Keep “High Level Abstraction” in your mind and design your architecture using polymorphism.
Polymorphism helps us to achieve kind of “Front Controller” pattern in java.
Implementing front controller pattern would
apply common logic to multiple requests.(TaxCalculator.calculate is single point call for all the objects)
separate system processing logic from the view.( Completed hidden implementation of subclasses)
centralize controlled access points into your system.( getInstance to get all the subclass objects).
Now I hope it is clear why we should use polymorphism and how to implement to get great design benefit out of it. Start using it or refactor your code to achieve this. Share your thought to others. Happy Coding !!!