Runtime Polymorphism | Dynamic Method Dispatch in Java
Overview
Dynamic Method Dispatch in Java is the process by which a call to an overridden method is resolved at runtime (during the code execution). The concept of method overriding is the way to attain runtime polymorphism in Java. During the code execution, JVM decides which implementation of the same method should be called.
What is Runtime Polymorphism in Java?
Dynamic Method Dispatch is another name for Runtime polymorphism in Java which originates with the concept of method overriding. In this case, the call to an overridden method will be resolved at the time of code execution (runtime) rather than the compile time.
The basis of dynamic method dispatch in Java starts with Inheritance where two or more classes exhibit a parent-child relationship. Now, there might be several versions of the same method in the parent as well as child classes or you can also call them superclass and subclasses.
It seems puzzling as to which version of the same method will be called. However, Java Virtual Machine (JVM) easily perceives the same during runtime based on the type of object being referred to.
In Java, the object creation occurs in part 2 with the new operator assigned to any class which denotes the type of object that will be created, and part 1 represents the reference variable. In the figure given above, the object created will be an instance of class A.
But remember that runtime polymorphism depends on the type of object being created (as in part 2) and not the reference variable (part 1).
When different classes that follow inheritance have the same method with the same name, parameters, and/or return type, it is known as method overriding.
Here, the reference variable is referring to the object of class B. The reference variable belongs to the superclass or parent class while the object is made up of the subclass or child class. It is also known as upcasting.
The subclasses exhibit an IS-A relationship with the parent class. For example, there can be a class MobileOS. Since both Android as well as iOS are mobile operating systems, they are the subclasses of MobileOS. So in terms of the IS-A relationship, we can say that Android "IS A" MobileOS and iOS "IS A" MobileOS.
The concept of upcasting can be seen in this example. Whether we create the object of Android or iOS, the reference variable is of the superclass in both cases, i.e., MobileOS.
Method Overriding
As mentioned earlier, when you can find the same method with the same signature (method name, parameters, and return type) in inherited classes, it leads to method overriding. The implementation of the class, i.e., the body of the class might differ in the overridden methods.
Therefore, the inherited classes having the same method with varied implementations make up an example of runtime polymorphism.
Advantages
- Runtime polymorphism in Java allows the superclass to define as well as share its own method and also allows the sub-classes to define their own implementation.
- The subclasses have the privilege to use the same method as their parent or define their specific implementation for the same method wherever necessary. Therefore, in one way, it supports code reusability when using the same method and implementation.
- It allows method overriding which is the basis for runtime polymorphism in Java.
Example of Java Runtime Polymorphism
Here, we'll consider the same example that has been described above.
Output:
Runtime Polymorphism with Data Members
Data members, in simple words, are nothing but variables.
There's one thing to keep in mind, methods can be overridden but not variables. Therefore, runtime polymorphism isn't valid for data members (variables).
Let's see an example where the superclass, as well as subclasses, will have a common variable speed. We'll create objects of the subclasses while the reference variable will still be of the same type as the superclass.
Output:
On accessing the value of the variable, it's clear that it doesn't change because overriding doesn't work on variables and it still refers to the variable of the parent class. So, the output remains 60.
Static vs Dynamic Binding
In all the above code examples, we didn't make any of these classes private, final or static. What if we did? Will there be any difference? The short answer is yes.
Actually, the methods in the above code examples are virtual by default but private, static, and final variables, as well as methods, use static binding which emphasizes the type of reference variable and resolves binding according to it. On the other hand, virtual methods use dynamic binding because it focuses on the type of object and resolves binding with the help of object creation.
Method overloading exhibits static binding or early binding because it is resolved at compile time. Method overriding, on the other hand, exhibits dynamic binding or late binding, which is resolved at run time.
Static Binding Let us take the same example of the mobile operating systems that we saw above, but we'll make all the methods static.
Output:
Now, the output didn't change even after we created a new object of the subclass. It's because static methods cannot be overridden in Java. So, JVM knows during compile time itself that it has to call the method of the parent class and not of the subclasses.
Dynamic Binding
Dynamic binding has been illustrated already in the above examples for runtime polymorphism. Let us look at the same code to understand what happens during dynamic binding.
Output:
Here, we haven't declared the methods as static, so they will be overridden. JVM cannot determine the method call just by looking at the reference variable only, so it has to wait till runtime to know the type of object and determine which method shall be invoked.
Conclusion
- Dynamic Method Dispatch or Runtime Polymorphism in Java is a way by which Java Virtual Machine (JVM) determines which version of the same method in the inherited classes should be called ruing the runtime.
- It follows dynamic or late binding where the method call will be done according to the type of object being referred to and not the reference variable.
- Runtime polymorphism in Java isn't applicable to data members. Methods can be overridden but not data members.
- Static binding focuses on the reference type and determines the method call during compilation itself. On the contrary, dynamic binding focuses on the type of object and the method call can be determined only during the runtime.