Overriding in Java

Last Updated : 29 Aug, 2026

Method overriding in Java allows a subclass to provide a specific implementation of a method that is already defined in its parent class. It is one of the key features of runtime polymorphism in object-oriented programming.

  • Access modifier cannot be more restrictive than the parent method
  • Achieved when child and parent classes have methods with the same signature
  • Static, final, and private methods cannot be overridden
Java
class Animal {
    
    void move(){
        System.out.println(
      "Animal is moving."); 
        
    }
    void eat(){
        
        System.out.println(
      "Animal is eating."); 
        
    }
}

class Dog extends Animal{
    
    @Override void move(){ 
        
      // move method from Base class is overriden in this
      // method
        System.out.println("Dog is running.");
    }
    void bark(){
        
        System.out.println("Dog is barking."); 
        
    }
}

public class Geeks {
    public static void main(String[] args)
    {
        Dog d = new Dog();
        d.move(); 
        d.eat(); 
        d.bark();
    }
}

Output
Dog is running.
Animal is eating.
Dog is barking.

Explanation: The Animal class defines base functionalities like move() and eat(). The Dog class inherits from Animal and overrides the move() method to provide a specific behavior Dog is running. Both classes can access their own methods. When creating a Dog object, calling move() executes the overridden method.

Rules for Method Overriding

  • Name, parameters, and return type must match the parent method.
  • Java picks which method to run at run time, based on the actual object type, not just the reference variable type.
  • Static methods cannot be overridden.
  • The @Override annotation catches mistakes like typos in method names.
Method Overriding in Java

Special Cases in Overriding

1. Calling Parent Method Using super

The super keyword can invoke the parent class method from the overriding method.

Java
class Parent{
    
    void show(){
        
        System.out.println("Parent's show()");
        }
}

class Child extends Parent{
    
    @Override
    void show(){
        
        super.show();
        System.out.println("Child's show()");
    }
}

public class Main{
    
    public static void main(String[] args){
        
        Parent obj = new Child();
        obj.show();
    }
}

Output
Parent's show()
Child's show()

Explanation:The Child class overrides the show() method of Parent. Inside the overridden method, super.show() explicitly calls the parent class implementation first. After that, the child class prints its own message. This shows how super can be used when the child needs both the parent and child behavior.

2. Final Methods Cannot Be Overridden

If we don't want a method to be overridden, we declare it as final. Please see Using Final with Inheritance. 

Java
class Parent{
    
    // Can't be overridden
    final void show(){
        
    }
}

class Child extends Parent{
    
    // This would produce error
    void show() {}
}

Explanation: The show() method in Parent is declared as final. This prevents subclasses from providing another implementation of that method. Therefore, declaring show() again in Child causes a compile-time error. A final method can be inherited and used by the child, but it cannot be overridden.

Output:

MethodOverriding

3. Static Methods

  • Static methods cannot be overridden; defining a static method in a subclass with the same signature as in the superclass hides the superclass method.
  • Instance methods can be overridden, but a subclass cannot override a superclass static method.
  • A static method in a subclass with the same signature as a superclass static method hides the original method.
Java
class Parent{
    static void staticMethod(){
        
        System.out.println("Parent static method");
    }
    void instanceMethod(){
        
        System.out.println("Parent instance method");
    }
}

class Child extends Parent{
    
    static void staticMethod(){
        
        // Hides Parent's static method
        System.out.println("Child static method");
    }
    @Override
    void instanceMethod(){ 
        
        // Overrides Parent's instance method
        System.out.println("Child instance method");
    }
}

public class GFG{
    
    public static void main(String[] args){
        
        Parent p = new Child();
        
        // Calls Parent's static method (hiding)
        p.staticMethod();
        
        // Calls Child's overridden instance method
        p.instanceMethod(); 
    }
}

Output
Parent static method
Child instance method

Explanation: The Parent class contains both a static method and an instance method. The Child class defines a static method with the same signature, which hides the parent's static method rather than overriding it. When p.staticMethod() is called using a Parent reference, the Parent static method executes. In contrast, instanceMethod() is an instance method, so runtime polymorphism applies and the Child implementation executes.

4. Private Methods

  • Private methods cannot be overridden because they are not visible to subclasses.
  • A subclass method with the same name is treated as a new, independent method, unrelated to the parent class.
Java
class Parent{
    
    private void display(){
        
        System.out.println("Parent private method");
    }
}

class Child extends Parent{
    
    void display(){
        
        // This is a new method, not overriding
        System.out.println("Child method");
    }
}

public class GFG{
    
    public static void main(String[] args){
        
        Child c = new Child();
        
         // Calls Child's method
        c.display(); 
    }
}

Output
Child method

Explanation: The display() method in Parent is private, so it is not inherited by Child. Therefore, the display() method declared in Child is a completely new method and does not override the parent's method. Calling display() through a Child object executes the method defined in Child.

5. Covariant Return Types

  • In method overriding, the return type of the overriding method can be a subclass of the return type of the overridden method.
  • This feature is known as covariant return type and allows more specific return types in the subclass.
Java
class Parent{
    
    Parent getObject(){
        
        System.out.println("Parent object");
        return new Parent();
    }
}

class Child extends Parent{
    
    @Override
    
    // Covariant return type
    Child getObject() {  
        System.out.println("Child object");
        return new Child();
    }
}

public class GFG{
    
    public static void main(String[] args){
        
        Parent obj = new Child();
        
        // Calls Child's method
        obj.getObject();  
        
    }
}

Output
Child object

Explanation: The Parent class defines getObject() with a return type of Parent. The Child class overrides it and returns a Child object. Since Child is a subclass of Parent, this is a valid covariant return type. When the actual object is a Child, the overridden Child method executes at runtime.

Exception-Handling in Overriding

  • The overriding method cannot throw new or broader checked exceptions than the method in the superclass.
  • It can throw fewer or narrower checked exceptions.
  • It can throw any unchecked exceptions (like RuntimeException) regardless of the superclass method.
Java
import java.io.IOException;

class Parent {
    void display() throws IOException {
        System.out.println("Parent method");
    }
}

class Child extends Parent {
    @Override
    void display() throws IOException {
        System.out.println("Child method");
    }
}

public class GFG{
    
    public static void main(String[] args){
        
        // Parent reference, Child object
        Parent obj = new Child(); 
        try{
            
            // Calls Child's overridden method
            obj.display(); 
        } catch (IOException e){
            
            System.out.println("Exception caught: " + e.getMessage());
        }
    }
}

Output
Child method

Explanation: The Parent class declares display() with throws IOException. The Child class overrides the method and also declares IOException, which is allowed because it is the same checked exception. The call is placed inside a try-catch block because the reference type Parent declares that the method may throw IOException. The program executes the Child implementation successfully.

Note: The example demonstrates an allowed case, but it does not demonstrate the restriction itself. For example, if the parent declares IOException, the child cannot override the method with throws Exception, because Exception is broader than IOException.

Real-Life Example: Employee Management System

Let’s understand overriding with a real-world analogy.

Imagine an organization’s Employee Management System. All employees share some behaviors like raiseSalary() and promote(), but the logic differs for different roles like Manager or Engineer. We can create a single Employee array where individual employees are of different types (sales, tech, etc) and call their functions. This simplifies the overall code a lot.

Java
abstract class Employee {

    abstract void raiseSalary();
    abstract void promote();
}

class Manager extends Employee{

    @Override void raiseSalary(){
        
        System.out.println(
            "Manager salary raised with incentives.");
    }

    @Override void promote(){
        
        System.out.println(
            "Manager promoted to Senior Manager.");
    }
}

class Engineer extends Employee{
    
    @Override void raiseSalary(){
        
        System.out.println(
            "Engineer salary raised with bonus.");
    }

    @Override void promote(){
        
        System.out.println(
            "Engineer promoted to Senior Engineer.");
    }
}

public class Company{
    
    public static void main(String[] args){
        
        Employee[] employees
            = { new Manager(), new Engineer() };

        System.out.println("--- Raising Salaries ---");
        for (Employee e : employees){
            
            e.raiseSalary(); 
        }

        System.out.println("\n--- Promotions ---");
        for (Employee e : employees) {
            e.promote();
        }
    }
}

Output
--- Raising Salaries ---
Manager salary raised with incentives.
Engineer salary raised with bonus.

--- Promotions ---
Manager promoted to Senior Manager.
Engineer promoted to Senior Engineer.

Explanation: Although both Manager and Engineer objects are referred to using the Employee type, Java calls the overridden methods of the actual objects at runtime, demonstrating dynamic method dispatch (runtime polymorphism).

Comment