Example of Method Overriding in Java
Rules for Java Method Overriding
1. Overriding and Access Modifiers
2. Final methods can not be overridden
3. Static methods can not be overridden(Method Overriding vs Method Hiding):
4. Private methods can not be overridden
5. The overriding method must have the same return type (or subtype)
6. Invoking overridden method from sub-class
In Java, Overriding is a feature that allows a subclass or child class to provide a specific implementation of a method that is already provided by one of its super-classes or parent classes. When a method in a subclass has the same name, the same parameters or signature, and the same return type(or sub-type) as a method in its super-class, then the method in the subclass is said to override the method in the super-class.
Method overriding is one of the ways by which Java achieves Run Time Polymorphism. The version of a method that is executed will be determined by the object that is used to invoke it. If an object of a parent class is used to invoke the method, then the version in the parent class will be executed, but if an object of the subclass is used to invoke the method, then the version in the child class will be executed. In other words, it is the type of the object being referred to (not the type of the reference variable) that determines which version of an overridden method will be executed.
Below is the implementation of the Java Method Overriding:
Java
// Java program to demonstrate
// method overriding in java
// Base Class
class Parent {
void show() { System.out.println("Parent's show()"); }
}
// Inherited class
class Child extends Parent {
// This method overrides show() of Parent
@Override void show()
{
System.out.println("Child's show()");
}
}
// Driver class
class Main {
public static void main(String[] args)
{
// If a Parent type reference refers
// to a Parent object, then Parent's
// show is called
Parent obj1 = new Parent();
obj1.show();
// If a Parent type reference refers
// to a Child object Child's show()
// is called. This is called RUN TIME
// POLYMORPHISM.
Parent obj2 = new Child();
obj2.show();
}
}
Output
Parent's show()
Child's show()
The access modifier 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 made public, but not private, in the subclass. Doing so will generate a compile-time error.
If we don’t want a method to be overridden, we declare it as final. Please see Using Final with Inheritance.
When you define a static method with the same signature as a static method in the base class, it is known as method hiding. The following table summarizes what happens when you define a method with the same signature as a method in a super-class.
Private methods cannot be overridden as they are bonded during compile time. Therefore we can’t even override private methods in a subclass.(See this for details).
From Java 5.0 onwards it is possible to have different return types for an overriding method in the child class, but the child’s return type should be a sub-type of the parent’s return type. This phenomenon is known as the covariant return type.
We can call the parent class method in the overriding method using the super keyword.
Java, as an object-oriented programming language, supports one of the key features of OOP - polymorphism. It allows objects to take on multiple forms, and one way it achieves this is through a mechanism called dynamic method dispatch. The feature plays a crucial role in achieving flexibility and extensibility in Java programs.
Before delving into dynamic method dispatch, it is important to grasp the concept of polymorphism. In Java, polymorphism allows objects to be treated as instances of their superclass, enabling code to work with objects of different types in a uniform way.
For example, if we have a superclass Animal and subclasses Dog and Cat, we can create an array of Animal objects and store instances of both Dog and Cat in it. We can then iterate through the array and call a method like makeSound() on each element, and the appropriate version of makeSound() from either Dog or Cat will be executed.
class Animal {
void makeSound() {
System.out.println("Generic Animal Sound");
}
}
class Dog extends Animal {
@Override
void makeSound() {
System.out.println("Bark");
}
}
class Cat extends Animal {
@Override
void makeSound() {
System.out.println("Meow");
}
}
public class Demo {
public static void main(String[] args) {
Animal[] animals = {new Dog(), new Cat()};
for (Animal animal : animals) {
animal.makeSound();
}
}
}
In this example, we have created an array of Animal objects and populate it with instances of Dog and Cat. When we call makeSound() on each element, the version defined in the subclass will be executed due to dynamic method dispatch.