Method Overriding (run time polymorphism)

Method overriding is achieved when a subclass provides the specific implementation of an instance method (i.e. non-static method) already defined in its superclass.

In this scenario, the method in superclass is called overridden method and the method in subclass is called overriding method. There must be an IS-A relationship (i.e. inheritance).

The new method definition must have the same method name and same parameter list.

Method overriding is an example of runtime polymorphism (i.e. dynamic binding) because the method to be invoked is determined at the runtime only.

 

Example 1

A program to explain the concept of Java method overriding is given below.

We have two classes here: a superclass Animal and a subclass Dog. The Dog class extends Animal class. Both the classes have a common method void makeSound(). Dog class is giving its own implementation to the makeSound() method or in other words it is overriding the makeSound() method.

The purpose of method overriding is clear here. Subclass wants to give its own implementation so that when it calls this method, it displays “Dog makes sound” instead of “Animal makes sound”.

OverrideTest.java

class Animal {  //superclass
void makeSound() {
System.out.println("Animal makes sound.");
}
}

class Dog extends Animal { //subclass
void makeSound() {
System.out.println("Dog makes sound.");
}
}

public class OverrideTest {
public static void main(String[] args) {
Dog d = new Dog();
d.makeSound(); // calls the subclass's version of makeSound()
}
}

Output:

Dog makes sound.

 

Method Overriding and Dynamic Method Dispatch

Method Overriding is an example of runtime polymorphism. When a superclass reference points to the subclass object then the call to the overridden method is determined at runtime, because during method call which method (superclass or subclass) is to be called is determined by the type of object. This procedure in which call to the overridden method is resolved at runtime is known as dynamic method dispatch.

Example 2

Let us see a coding example below to understand this concept:

DynamicMethodDispatch.java

class A { //superclass
int x;

A(int x) {
this.x = x;
}

void show() {
System.out.println("From superclass");
System.out.println("x = " + x);
}
}

class B extends A { //subclass
int y;

B(int x, int y) {
super(x);
this.y = y;
}

void show() {
System.out.println("From subclass");
System.out.println("x = " + x);
System.out.println("y = " + y);
}

public void ownMethod() { // own method of subclass
System.out.println("Own method of subclass");
}

}

public class DynamicMethodDispatch {
public static void main(String[] args) {
A a; //superclass reference
a = new A(10);
//call to the show() method of superclass
a.show();
a = new B(20, 30);
//call to the show() method of subclass
a.show(); //dynamic method dispatch or runtime polymorphism
}
}

Output:

From superclass
x = 10
From subclass
x = 20
y = 30

 

Rules for Method Overriding

  • Both the superclass and the subclass must have the same method name and the same parameter list. The return type of overriding method is same or sub-type (covariant return type) of the return type of overridden method.
  • We cannot override the method declared as private, final and static.
  • We should always override abstract methods of the superclass.
  • The access specifier for an overriding method can allow more, but not less, access than the overridden method (discussed later).

 

Covariant Return Type

Before Java SE 5, it was not possible to override a method by changing the return type. When we override a superclass method, the name, parameter list and return type of the overriding method in subclass has to be exactly same as that of parent class method. Overriding method was said to be invariant with respect to return type.

But, Java SE 5 onward it is now possible to have different return type for a overriding method in subclass, but sub’s return type should be sub-type of super’s return type. Overriding method becomes variant with respect to return type.

Example 3

See the following example for covariant return type.

CovariantTypeDemo.java

class X {  }

class Y extends X { }

class Super {
X method() {
System.out.println("Super method()");
return new X();
}
}

class Sub extends Super {
Y method() {
System.out.println("Sub method()");
return new Y();
}
}

public class CovariantTypeDemo {

public static void main(String[] args) {
Super ob = new Super();
ob.method();

Sub obj = new Sub();
obj.method();
}
}

Output:

Super method()
Sub method()

 

Access Specifier and Method Overriding

The access specifier rule for an overriding method can allow more, but not less, access than the overridden method. For example, a protected instance method in the superclass can be overridden as public, but not private, in the subclass. Doing so, will generate compile time error.

Example 4

See the following example for access specifier with method overriding.

OverrideAccess.java

class Parent {
protected void disp() {
System.out.println("Parent class");
}
}

class Child extends Parent {
public void disp() {
System.out.println("Child class");
}
}

public class OverrideAccess {

public static void main(String[] args) {
Parent p; //superclass reference
p = new Parent(); //object of superclass
p.disp();
p = new Child(); //object of subclass
p.disp();
}
}

Output:

Super class constructor
Super class constructor
Sub class constructor

NOTE: To know about method overriding associated with throws clause, see this topic: Java throws with method overriding.