Compile-time vs. Runtime polymorphism in Java

Polymorphism in Java

In OOP, polymorphism is a technique by which a program can exhibit different behaviors based on some input. The concept is very similar to the principle of biological polymorphism, where a species has various forms of existence.

Polymorphism allows us to code to an interface and has multiple implementations, making the program better. In Java, there are two types of polymorphism:

  • Compile-time polymorphism
  • Runtime polymorphism

The first type is implemented with method overloading, and the second one is implemented via method overriding. We’ll learn about these two types and techniques in detail in the upcoming sections.

Compile-time polymorphism

In compile-time polymorphism, the compiler resolves the method calls during compilation. Since this process happens statically, it is also called static polymorphism and exhibits static/early binding. In Java, it is implemented via method overloading.

Method Overloading

Method overloading is a technique that allows multiple methods within a class to have the same name with different argument lists. See this blog to study how method overloading is achieved.

Consider a scenario where we have different methods for each kind of addition:

int addTwo (int first , int second) {
    //logic
}
int addThree (int first , int second , int third) {
    //logic
}

With method overloading, this can be written as:

int addition (int first , int second) {
       //Implementation code
}
int addition (int first , int second , int third) {
       //Implementation code
}

The main advantage of method overloading is that it enhances code readability and flexibility. The optimized code has a single method name that is, it makes more sense and increases readability. Also, the compiler resolves the calls, so we don’t need to make sure we call the proper method (like we had to do in unoptimized code); hence, flexibility is also increased.

Runtime Polymorphism

In this type of polymorphism, the JVM resolves which block of code will be executed during runtime, also known as dynamic polymorphism. Since the resolves are made during runtime thus, it supports dynamic or late binding. In Java, it is implanted via method overriding.

Method Overriding

Method overriding comes into the picture when we deal with inheritance. We override a method of the superclass to provide meaningful or custom implementation according to the subclass.

  • The overriding method (present in the child class) and overridden method must have the same prototype.
  • Any method bonded at the compile-time can not be overridden like static methods.

Example

public class Base {
       //...
       public void ovrMethod (int a){
              //implemention
       }
}
public class Child extends base {
       //...
       @Override
       public void ovrMethod (int a){
              //modified implemention
       }
}
//using the methods.
//ref is assigned Child instance
Base ref = new Child();
//Child ovrMethod is called
ref.ovrMethod(0);
//ref is assigned Base instance
ref = new Base();
//Base ovrMethod is called
ref.ovrMethod(0);

Working of method overriding

Generally, we call overridden method with the base class’s reference by creating a reference of the base type and assigning it an instance of the child class (using the new keyword). To understand more about runtime polymorphism, one needs to understand typecasting in java; refer to this blog.

When ovrMethod() is used via the reference ref, the decision of which method to call is taken at runtime. If ref is assigned an instance of the child class, then the overriding method is called; otherwise, if ref points to an instance of the base class, the overridden method is called.

Comparison between Compile-time and Runtime polymorphism

  • Resolution: In compile-time polymorphism, the compiler resolves the method call at compile-time (static binding). In runtime polymorphism, it is resolved at runtime(dynamic binding) by the JVM.
  • Implementation technique: In Java, compile-time polymorphism is implemented by method overloading, whereas runtime polymorphism is done by method overriding.
  • Involvement of inheritance: Inheritance is not necessary for compile-time polymorphism, but it is a must in runtime polymorphism because then only one can override methods.
  • Difference between involved methods: In compile-time polymorphism, each overloaded method must have a different signature but the same name. Still, in runtime polymorphism, each method (involved in overriding) must have the same prototype (everything must be the same except the implementation of the method).
  • Static method: The static method can be overloaded but can’t be overridden because it is resolved at the compile time. Hence, a static method can be involved in compile-time polymorphism but not in runtime polymorphism.
  • Execution rate: It is said that compile-time polymorphism provides fast execution because the methods which will be executed are known at compile-time, whereas, in runtime polymorphism, execution is comparatively slower because the resolves are done during runtime.

Conclusion

In this blog, we first understood polymorphism and its importance. Further, we explored the types and techniques by which they are implemented in Java. Finally, we had a comparative study of the two types — compile-time and runtime polymorphism in almost every aspect.

Enjoy learning.

More From EnjoyAlgorithms

Our weekly newsletter

Subscribe to get free weekly content on data structure and algorithms, machine learning, system design, oops design and mathematics.

Follow Us:

LinkedinMedium

© 2020 EnjoyAlgorithms Inc.

All rights reserved.