Monday, July 26, 2010

Runtime Polymorphism and Compile time Polymorphism is explained


Target audience: Beginners

Let’s look at some basics before get into details

What is polymorphism?
Polymorphism is one in many forms. That’s it. We can see lots of examples in real time. If you think about a Dog, A Dog is an Animal. A Dog can be a pet. So a Dog can be in
many forms. The Dog is Animal type and it can be another type of Pet.
Apart from types, behaviours can also take part of Polymorphism. For Example, Animals can swim. A Dog can swim, A Monkey also can swim. Dog and Monkey has their own way of swimming. Here, the swimming behavior is in many forms. A monkey can walk with two legs and also with four legs. Here, walking behaviour is in many forms. These are the examples for polymorphism in real world.

Let’s see how Polymorphism works in Java. Polymorphism allows you define a Super type and have multiple subtype implementations. There Are Two Types of Polymorphism in Java. One is compile time Polymorphism and it is sometimes referred as static Polymorphism and the other one is Runtime Polymorphism and it is sometimes referred as dynamic Polymorphism

Runtime Polymorphism
As we can have multiple subtype implementations for a super type, Java virtual machine determines the proper type to be invoked at the runtime. Method overriding is a runtime polymorphism. For example look at the following example. I have Worker interface(Super type) and have Teacher and Principal classes ( Subtypes) that implements the Worker interface .The Worker interface has a method doIt() and the subtypes implements that method.


// Worker class
interface Worker {
public void doIt();
}

// Teacher class
class Teacher implements Worker {
public void doIt() {
System.out.println("Teacher does the work");
}
}

//Principalclass
class Principal implements Worker {
public void doIt() {
System.out.println("Principal does the work");
}
}

Now I’m going to have another class which has a main method. The main method creates a List and adds a Principal instance and a Teacher instance to that list. Then it iterates through the list, refer the instances by their super type and calls the doit() method on the Super type reference

public class PolymorphismExample {

public static void main(String[] args) {
List workers = new ArrayList();

//Adding worker one
Worker worker1 = new Principal();
workers.add(worker1);

//Adding worker two
Worker worker2 = new Teacher();
workers.add(worker2);

for (Iterator iterator = workers.iterator(); iterator.hasNext();) {
Worker worker = (Worker) iterator.next();
worker.doIt();
}

}
}

If you run the PolymorphismExample class then the output will be

Principal does the work
Teacher does the work

If you see carefully, we cannot see which instance is called. We called doIt() method only on the Super type Worker but the JVM finds the proper type and called its implementation of doIt() method. This is Runtime Polymorphism. The JVM determines proper type only at runtime

Compile time Polymorphism
Method overloading is a compile time Polymorphism. As we can have multiple subtype implementations for a super type, the compiler determines which type to be invoked at the compile time. For example look at the following example. I’m going to change PolymorphismExample class to have some overloaded methods

public class PolymorphismExample {

public void doSomething(Worker worker) {
System.out.println("I'm a worker");
}

public void doSomething(Teacher teacher) {
System.out.println("I'm a Teacher");
}

public void doSomething(Principal principal) {
System.out.println("I'm a Principal");
}

public static void main(String[] args) {

PolymorphismExample example = new PolymorphismExample();
Worker principal = new Principal();
Worker teacher = new Teacher();

example.doSomething(principal);
example.doSomething(teacher);
}
}

You would expect the output as bellow, If you run the PolymorphismExample class

I'm a Principal
I'm a Teacher

WRONG, the actual output will be

I'm a worker
I'm a worker

Here the type is decided at compile time. Even though the objects are instances of Principal and Teacher, the reference is a Worker type. So the compiler picks the doSomething(Worker worker) method as it accepts the same type of reference type (Worker).
So keep it in mind when you use method overloading.

10 comments: