Runtime Polymorphism in Java

Quite a long time back I had written about Overriding v/s Hiding. In this post I would like to explain in brief with examples about Runtime polymorphism in Java. This post should have been written before Overriding v/s Hiding, but better late than never.

Let us consider the following Vehicle and Car and Truck class:

class Vehicle{
  public void drive(){
    System.out.println("Driving vehicle ...");
  }
}

class Car extends Vehicle{
  @Override
  public void drive(){
    System.out.println("Driving car...");
  }
}

class Truck extends Vehicle{
  @Override
  public void drive(){
    System.out.println("Driving truck...");
  }
  
  public void load(){
    System.out.println("Loading truck...");
  }
}

A Vehicle can be driven, so is a Car and Truck. But in addition to this a Truck can also be loaded with goods. Let us create instances of these classes and drive() them and try to also load() the truck.

public class RunTimePolymorphismDemo {
  public static void main(String[] args) {
    Vehicle vehicle = new Vehicle();
    vehicle.drive();
    
    Vehicle carVehicle = new Car();
    carVehicle.drive();
    
    Vehicle truckVehicle = new Truck();
    truckVehicle.drive();
    
    //Compile time error
    //truckVehicle.load();
    
    Truck truck = new Truck();
    truck.load();
  }
}

And the output is:

Driving vehicle ...
Driving car...
Driving truck...
Loading truck...

Had the runtime polymorphism not kicked in, the output would have been: Driving vehicle ... for all the three invocations of drive() method. You can also see that truckVehicle.drive() results in a compile time error. So what’s happening in the above code?

Any object declaration and instantiation has 2 parts in it: The type of the reference and the type of the object created. For example in Vehicle carVehicle = new Car() the reference type is Vehicle and the object created is of type Car. Such an assignment is only possible when the object created type is a subclass of the reference type i.e in cases where inheritance is used.

Each object reference can be used to invoke methods and the methods which can be invoked is decided based on the reference type. And this is decided during the compile time. But the implementation to be invoked is decided based on the type of the object created. In the above example: carVehicle.drive() compiles because the drive() method is part of the Vehicle class and gives Driving car... as the output because the method is overridden by the Car class. On similar lines: truckVehicle.load() gives compile time error because the method load() is not part of the Vehicle class, but is defined only in the Truck class. But the truck.load() compiles because the reference type is Truck class and the compiler can resolve the load() method.

To summarise:

  • The method binding happens at the compile time i.e which methods can be invoked on a given reference type is decided at the compile time.
  • The selection of the method’s implementation to execute happens at the run time i.e which implementation of the method to be executed i.e the super class version or one of the subclass’s version is decided at the run time and this is what leads to the runtime polymorphism.

There are plenty of places where runtime polymorphism is leveraged, few which I can state: Dependency Injection, Coding to Interface.

1 thought on “Runtime Polymorphism in Java”

Leave a Reply

Discover more from Experiences Unlimited

Subscribe now to keep reading and get access to the full archive.

Continue reading