This tutorial explains how to achieve Runtime Polymorphism in Java using Method Overriding and @override annotation with simple examples:
We have already discussed the polymorphism concept and Compile-time polymorphism in detail. In this tutorial, we will go ahead with Runtime polymorphism in Java.
In contrast to compile-time polymorphism in which method call is resolved at compile-time, in runtime polymorphism, the method call is resolved at runtime.
=> Check ALL Java Tutorials Here.
Table of Contents:
Runtime Polymorphism In Java
A runtime polymorphism which is also known as dynamic polymorphism or Dynamic Method Dispatch is a technique in which an overridden method call is resolved dynamically at runtime.
Runtime polymorphism in Java is achieved by using “method overriding”. Method overriding is a technique by which a method in the parent class is redefined or overridden in the child class.
When the method is overridden in a class, the dynamic method dispatch technique resolves the overridden method call at runtime and not at compile time.
Achieve Runtime Polymorphism In Java – Method Overriding
Method overriding is the approach we use to achieve runtime polymorphism in Java. As already mentioned, method overriding is a technique in which subclass adds a method that is already present in its parent class and adds new functionality to this method. Then we say that the base class method is overridden.
The new method we defined in the subclass with the same prototype as the method of the parent class but different implementation is called the “overriding method”. The method in the parent class is known as the “Overridden method”.
Once the method is overridden, the question remains as to how the call to this overridden method is resolved?
We usually call the overridden method through the base class’s reference. We will create a reference of type base and then assign a child class object using the new keyword.
Thus it depends on the contents of the reference variable or which object is referenced by the base class reference that determines which method is to be called. So if the reference objects point to the object of the child class, then the overriding method is called.
Otherwise, if the reference object contains a base class object then the overridden method is called. One topic we need to be clear in runtime polymorphism especially for dynamic method dispatch is “Upcasting” which is explained below.
Upcasting
When a reference object of the parent class we discussed above points to or refers to the object of the subclass, then we call it Upcasting.
Let’s understand upcasting using a simple example.
Consider that we have a class ‘BaseClass’ and we extend this BaseClass to create a new class DerivedClass. This structure looks as shown below.
class BaseClass { ….//BaseClass code here } class DerivedClass extends BaseClass{ ….//DerivedClass code here }
Now to implement upcasting we will declare a reference variable of type BaseClass. Next, we assign an object of DerivedClass to the reference of class BaseClass as done in the below code statement.
BaseClass base = new DerivedClass (); //Upcasting
So here we can say that we have upcast the DerivedClass object to BaseClass. As far as runtime polymorphism is concerned the concept of upcasting is very important.
Thus in general, upcasting is the process of assigning child or subclass objects to the reference of a parent or superclass.
SuperClass reference = new Subclass Object;
The Java program below demonstrates method overriding and also shows how upcasting is performed to resolve overridden method calls at runtime.
//base/parent class class Parent { void Print() //print method { System.out.println("Parent::Print() method"); } } //child class 1 inheriting from Parent class child1 extends Parent { void Print() //overridden print method { System.out.println("child1::Print() method"); } } //child class 2 inheriting from Parent class child2 extends Parent { void Print() //overridden print method { System.out.println("child2::Print() method"); } } class Main { public static void main(String[] args) { Parent parent = new Parent(); parent.Print(); //executes parent Print () method parent = new child1(); //upcasting parent.Print(); //executes child1 Print () method parent = new child2(); //upcasting parent.Print(); //executes child2 Print () method
Output:
In the above program, we have two classes i.e. child1 and child2 which are both derived from a ‘Parent’ class. Parent class has a method ‘Print’ which is overridden in both child1 and child2 classes. Then in the main method, we create a reference object of the Parent class named ‘parent’.
First, we assign it an object of the Parent class and then call the “Print() “ method. Then we repeat this by assigning first the child1 object and then the child2 object to the Parent reference.
The output shows, depending on the contents of the parent reference, and the appropriate Print method is called.
Advantages Of Dynamic/Runtime Polymorphism
- With dynamic polymorphism, the programmer is allowed to override methods.
- It allows classes to define a method with general implementation which its derivatives can then override and provide the specific implementation.
- With dynamic method dispatch, the method call is resolved at runtime, unlike overloading which is decided at compile time. This allows more flexibility for the programmers.
As runtime polymorphism binds the appropriate method to the call at run time and we also call it dynamic binding or late binding. Compile-time polymorphism on the other hand supports static binding or early binding.
Static vs. Dynamic Binding
Static binding | Dynamic binding |
---|---|
Method call resolved at compile time is static binding. | Method call resolved at runtime is dynamic binding. |
Method overloading is an example of static binding. | Method overriding is an example of dynamic binding. |
Class and field types are used for static binding. | Objects are used for dynamic binding. |
Private, final and static entities use static binding. | Virtual methods use dynamic binding. |
Virtual Function/Method In Java
Virtual function or method in Java is a feature that is used with Runtime polymorphism. Unlike C++, Java doesn’t have a special ‘virtual’ keyword to denote that a method is virtual. A method that is defined in the base class and overridden in the derived class is virtual.
In Java, by default, every non-static method except for private and final is a virtual function. So note that the methods we discussed above overriding to implement runtime polymorphism are also virtual methods.
As the static method is bound to Class and cannot be called using an object, it cannot be used with runtime polymorphism and it is also not a virtual function.
Interfaces in Java are by default virtual. Classes implementing interfaces provide implementations for the interface methods. As in runtime polymorphism, call to interface methods is also resolved at runtime.
Remember that since methods in an interface are designed to be overridden, all interface methods are virtual functions.
For example consider the following code:
interface car{ void accelerate(); } class Maruti implements car{ void accelerate () { System.out.println(“Maruti car accelerated!!”); } }
In the above code, the method accelerate () is a virtual function as it is a part of the interface car and is designed to be overridden.
@override Annotation In Java
The @override annotation is the default annotation in Java. This annotation was introduced in Java 1.5. The @override annotation is used when the subclass method overrides its superclass method.
By using Java @override annotation to indicate that the method is overriding its parent class method, a compiler issues a warning if the annotated method is not overridden. So makes it compulsory for the method to be overridden when the @override annotation is used.
Secondly, by using the @override annotation we make the code more readable. We can at once realize that the method being declared is to be overridden.
The general syntax of Java @override annotation is
public @interface override
The below Java program shows the usage of @override annotation.
//base class definition class BaseClass { public void display() { System.out.println("BaseClass::display () method"); } } //derived class inheriting base class class DerivedClass extends BaseClass { @Override //indicates the display method being overridden public void display() { System.out.println("DerivedClass::display () method"); } } // main class public class Main { public static void main(String args[]) { System.out.println("@Override Example"); //BaseClass type object;contain child object BaseClass testObj = new DerivedClass(); //call display method based on contents of object i.e. derived class display () testObj.display(); } }
Output:
In the above program, we have a BaseClass that defines a display method. Then we derive a class DerivedClass from this BaseClass and mark the display method with the @override annotation. This method is overridden in the DerivedClass.
In the main method, we create a BaseClass object reference and point it to the DerivedClass object which causes the reference to call the DerivedClass display method.
If we had not implemented the display () method in the Derived class, then the compiler would have given a compiler warning as it is marked with @override annotation.
Overloading And Overriding In Java
Now that we have discussed both overloading and overriding in Java, let’s summarize these two concepts.
Overloading is related to compile-time polymorphism i.e. we implement compile-time polymorphism using overloading. Overloading is done in two ways i.e. Method overloading and Operator overloading.
Method overloading is the technique in which we have more than one method with the same name but different parameter lists. The parameter list is differentiated based on the number of parameters, types of parameters, or sequence of parameters.
Operator overloading in Java is limited and it allows us to overload only the ‘+’ operator which is used to add two numbers and concatenate two String objects.
Overloading is resolved at compile time and is static. It is also called ‘Early binding’.
Method Overriding is a feature using which we implement runtime polymorphism. In method overriding, a method of the parent class is overridden in the child class. This means, that the method prototype in both super and subclass remains the same but the implementations are different.
Method overriding uses the dynamic method dispatch technique to resolve the method call and decide whether to call a superclass or subclass method and this is done at runtime.
Hence runtime polymorphism is also called dynamic polymorphism or late binding.
Next, let’s tabularize the differences between overloading and overriding in Java.
Overloading Vs Overriding In Java
Overloading | Overriding |
---|---|
Overloading is used in compile-time polymorphism. | Overriding is implemented in runtime polymorphism. |
Can be done in the same class. May or may not require inheritance. | Overriding always requires inheritance. |
Methods are overloaded with the same method name and different parameter list. | Overridden methods have the same prototypes. |
The return type is not considered in method overloading. | Return type should be the same in overridden and overriding methods. |
Improves the readability of the program. | Overriding allows having specific implementation class wise. |
Frequently Asked Questions
Q #1) Can we override the static method?
Answer: No. Static methods cannot be overridden in Java. This is because static methods are class-based and are called by class directly. They don’t need objects to invoke at runtime. Hence the static method dispatch is determined by the compiler.
Q #2) Can we override constructor?
Answer: No, we cannot override a constructor. A constructor is called when the object is created. It is not called an object. Also, one of the requirements of overriding is the overridden method and the overriding method should have the same method signature which is not possible in the case of constructors.
Q #3) Why is method overriding called as Dynamic Polymorphism?
Answer: In the case of method overriding, the method call is resolved dynamically at runtime. Hence it is called dynamic polymorphism.
Q #4) What is the use of Dynamic Polymorphism in Java?
Answer: Dynamic polymorphism uses a dynamic method dispatch technique that supports method overriding so that the subclass can provide specific implementation to the overridden method. This way we can implement the specific features that allow us to write efficient programs.
Secondly, we also need not worry about resolving method calls as dynamic method dispatch decides which method to call.
Q #5) What is the difference between Static and Dynamic Binding?
Answer: The linking between a method call and its implementation is called binding. When this linking is resolved at compile-time, we call it as static binding. When the binding is done dynamically at run time, then we call it as dynamic binding.
The static binding uses the data type of class and fields to resolve method calls. The dynamic binding uses objects to resolve method calls. Static binding is also called compile-time polymorphism and dynamic binding is also called runtime polymorphism.
Conclusion
In this tutorial, we have discussed runtime polymorphism in Java in detail.
Runtime polymorphism is implemented using method overriding. Method overriding is done in the subclass wherein a method defined in the superclass is redefined or overridden in its subclass. The method signature remains the same in the super and subclass.
By using method overriding we can provide specific implementation to the same method in the subclass. This way, we can write more efficient programs that involve inheritance. Java provides @override annotation to indicate that the method is to be overridden.
By default, all non-static methods that are not final are virtual in Java. All virtual methods can be overridden.
=> Watch Out The Simple Java Training Series Here.