
What is it?
Google definition for the word polymorphism is
“The condition of occurring in several different forms”
Actually, in oop, the concept is much closer to this general definition. We’ll see. First, let me remind you one of our previous examples in the inheritance tutorial.
There, we have written an example code for a Class called Tree.
This Class represent a basic concept of a Tree. It has some member variables and 2 methods called printTreeDetails() and draw() to output the details of the Tree object and to draw the tree on the screen respectively.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
public class Tree{ public double height; public int branchesNo; //............. public void printTreeDetails(){ System.out.println(“Height of the tree :”+height); System.out.println(“Number of branches :”+branchesNo); } public void draw(){ //............. } } |
We have also created a Child class of the Tree Class called OrangeTree using the extends keyword. So, this OrangeTree has inherited features of the Class, Tree.
1 2 3 4 5 6 7 |
public class OrangeTree extends Tree{ public boolean hasLeaves=true; public void addFruits(int noOfFruit){ //................... } } |
This OrangeTree has 2 new items. A member variable called hasLeaves and a method addFruits().
In addition to them, all methods and variables in the parent class are also available.
So, the printTreeDetails() and draw() methods in the parent Class Tree are available in the OrangeTree as well.
But, of course, we can override the methods in the parent class to our own definition if we want.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
public class OrangeTree extends Tree{ public boolean hasLeaves=true; public void addFruits(int noOfFruit){ //............. } public void printTreeDetails(){ // the code inside this printTreeDetails() method is different // from the code of the printTreeDetails() method in the parent // class, Tree. System.out.println(“Height of the tree :”+height); System.out.println(“Number of branches :”+branchesNo); // this is the part added new!!! System.out.println(“Does the tree have leaves? :”+hasLeaves); //.............. } } |
Note that we have overridden the printTreeDetails() method. NOT Overloading. The words and meanings are different. In a previous tutorial of Java Constructors,we discussed about the overloading. There, in order to do overloading, we had to change the signature of the method.
But here, in overriding, we don’t change the signature of the method!! Note that. We replace the original printTreeDetails() method in the parent class with a NEW printTreeDetails() method with a different implementation. Of course, you can see, a new feature
The keyword super
Now what happens if we want to call old printTreeDetails() method of the Tree Class inside the OrangeTree? If we just call printTreeDetails() method, we are now calling the new printTreeDetails() method since we have overridden the old code.
But we have a way to call the original printTreeDetails() method.
Use, super keyword.
For an example, in the new printTreeDetails() method of the Class OrangeTree we are typing the same old code again
1 2 3 |
System.out.println(“Height of the tree :”+height); System.out.println(“Number of branches :”+branchesNo); |
Instead, we can use super keyword and call the old method…
1 2 3 4 5 6 7 8 9 10 |
public void printTreeDetails(){ super.printTreeDetails(); // this is the part added new!!! System.out.println(“Does the tree have leaves? :”+hasLeaves); //........... } |
See, without the calling to the previous printTreeDetails() method, we had to type the same thing in the old method. But everything becomes simplified with the use of super keyword.
Now, you can understand the importance of the super keyword. If we want everything inside the old printTreeDetails() we don’t need to retype the same information. Just use the super!
But still we didn’t discuss the technique polymorphism.
Here it is…
The Abstract Thinking
Can you imagine a tree?
Of course you can. It would probably be something like this…
But there are no such generalized trees in real world 🙂 Yes there are Orange trees, apple trees, mango trees…but no “just” trees. There has to be a specific kind of tree in reality like orange, apple or mango.
Think of another example…, say, vehicle.
Can you imagine a vehicle?? Now you might have imagined a car, bike or a bus for example. But you can’t imagine the meaning of the term “vehicle”. So, a vehicle is called an “abstract” concept. Such concepts do not represent or imitate external reality or the objects of nature…Tree, for example, is an abstract concept. It is not available in nature directly, but in different forms as apple, mango or orange. Same is applied to Vehicle as well.
This Abstract concept is used in Java. Since there are no any objects of Tree or Vehicle Classes in real world, we don’t need to create objects of Tree or Vehicle. That means,
1 |
Tree tree1 = new Tree(); |
or
1 |
Vehicle myVehicle = new Vehicle(); |
is not necessary. So, we declare the Classes Tree and Vehicle as “abstract” Classes. For that, we use the keyword “abstract” in the Class declaration.
1 2 3 |
public abstract class Tree{ //............... } |
1 2 3 |
public abstract class Vehicle{ //............... } |
like that.
Now attempting to create an object of Tree or Vehicle in anywhere produces an error!
1 |
Tree tree1 = new Tree(); // ERROR! |
1 |
Vehicle myVehicle = new Vehicle(); // ERROR! |
Finally, here comes the polymorphism
Now, can you remember the draw() method we have declared in the Class Tree? But I have already mentioned you there’s no any Tree in real world. So we can’t actually draw a Tree (Of course, you can draw a rough tree sketch like the previous image I’ve drawn 🙂 But, it’s useless in a complex 3D game, since there are different kinds of trees there)
Similarly, in The Class Vehicle, If there’s a method called draw(), it’s useless. We cannot draw something that we cannot imagine!! Can we?
So, draw() method actually comes useful in the child Classes. For example, we can imagine and an orange tree. So we CAN draw an orange tree. Similarly, we can draw a Car. So, The Child classes should have the actual implementation of the draw() method.
But, there’s another problem. Notice that Orange tree is different from an Apple tree. Car is different from a Motorbike. So, each child class MUST have different draw methods!
Now this is called polymorphism. There’s only one draw() method that the child classes inherit from the parent Class. But, their actual implementations are different from one child to the other!
That means, each child class should override the draw() method of the parent class and write their own implementation.
Then, one question remains. What would be the code for draw() method in the parent class? It is also an abstract concept. We can’t draw something we can’t imagine. So the method itself is abstract as well!
Therefore, just keep it blank!
1 |
public void draw(){} |
🙁 This might look ugly. You can again use the abstract keyword here as well and exclude the “{}” part.
1 |
public abstract void draw(); |
Now, a beautiful thing happens.
Any Class that is a child class of the abstract class with the abstract method draw() must implement the draw() method!!!
That means, for example, OrangeTree child Class now definitely MUST override the draw() method of the Tree Class and implement it with its own code. You cannot escape from it. As long as OrangeTree extends the Tree Class, it must implement all abstract methods of the Tree Class.
There will be an error if we didn’t do that!
That’s all about polymorphism. In this tutorial, you have learnt many other important concepts besides polymorphism. Abstract Class and super keyword are two other very important things that you should understand thoroughly! In the next tutorial, we’ll see another important programming part called “nested classes”, where you write a Class inside a Class.