Method Overriding in Java

Method Overriding in Java allows a subclass (or child class) to provide a specific implementation of a method which is already defined in its super class (or parent class). When a method in a subclass has the same name, parameters and return type as the method defined in its super class, then the subclass class overrides the method of the superclass.

In other words, If a subclass provides the specific implementation of a method that is already declared by one of its parent class, it is known as method overriding.

Method overriding in java is used to achieve Run Time Polymorphism. It means, is the mechanism by which a call to an overridden method is resolved at run time, rather than compile time.

Which version of the method needs to be executed is determined by the object that is used to invoke it. If an object of a super class is used to invoke the method, then the method version in the super class is executed whereas if an object of the subclass is used to invoke the method, then the method version in the child class is executed.


Syntax of Method Overriding

Let's look at the syntax of method overriding in Java. Consider a superclass Animal with a method makeSound():

// Superclass
class Animal {
    void makeSound() {
        System.out.println("Generic animal sound");
    }
}

// Subclass overriding the makeSound() method
class Cat extends Animal {
    @Override
    void makeSound() {
        System.out.println("Meow");
    }
}
In this example, the Cat class is a subclass of Animal, and it overrides the makeSound() method to provide a specific implementation for a cat's sound.
Rules for Method Overriding
  • Method Signature : The method in the subclass must have the same method signature (name, return type, and parameter types) as the method in the superclass.

  • Access Modifier : The access modifier of the overriding method in the subclass cannot be more restrictive than the overridden method in the superclass. For example, if the superclass method is protected, the subclass method can be either protected or public.

  • Exception Handling : If the overridden method in the superclass declares an exception, the overriding method in the subclass can declare the same, subclass exception, or no exception. However, it cannot declare a broader exception.
    // Superclass with an overridden method
    class Superclass {
        void exampleMethod() throws Exception {
            // Implementation
        }
    }
    
    // Subclass overriding the method with a narrower exception
    class Subclass extends Superclass {
        @Override
        void exampleMethod() throws RuntimeException {
            // Implementation
        }
    }
    
  • A method declared final in parent class cannot be overridden.

  • A method declared static in parent class cannot be overridden.

  • Constructors cannot be overridden.

  • If a method cannot be inherited, then it cannot be overridden.

  • If a class is extending an abstract class or implementing an interface then it has to override all the abstract methods unless the class itself is a abstract class.


Java program for method overriding

class Bird {
  String birdtype;

  Bird(String birdtype) {
    this.birdtype = birdtype;
  }
  public void move() {
    System.out.println(birdtype + " is Flying");
  }
}

class Ostrich extends Bird {
  Ostrich(String birdtype) {
    super(birdtype);
  }
  public void move() {
    System.out.println(birdtype + " is Running");
  }
}

public class MethodOverriding {
  public static void main(String[] args) {
    // Create object of parent class
    Bird bird = new Bird("Crow");
    // Create object of child class
    Ostrich ostrich = new Ostrich("Ostrich");
    // Invoke move() of parent class
    bird.move();
    // Invoke move() of child class
    ostrich.move();
  }
}
Output
Crow is Flying
Ostrich is Running

In the above program, the move() method is present in both Bird superclass and Ostrich subclass. As we know, that Ostriches cannot fly like other birds. Hence, we have overriden the move() method in Ostrich class.

When we call move() using the bird object (object of the super class), the method inside the Bird is invoked whereas when we call move() using ostrich object (object of the sub class) the method inside the Ostrich is invoked.


Invoking overridden method of parent class

As we know that, when we override a method in child class, then call to the method using child class object calls the overridden method of child class. A common question that arrises in our mind is

Can we access the overridden method of the parent class from child class ?

Yes, we can. We can call parent class overridden method from child class using super keyword. Here is a java program to access overridden method of parent class from child class.

class Driver {
  // overridden method
  public void getInfo() {
    System.out.println("I am a Driver.");
  }
}

class TruckDriver extends Driver {
  // overriding getInfo method
  public void getInfo() {
    // calling base class overridden method.
    super.getInfo();
    System.out.println("I am Driving a Truck.");
  }
}
public class MethodOverridingSuper {
  public static void main(String[] args) {
    TruckDriver truckDriver = new TruckDriver();
    // Calling overridden method
    truckDriver.getInfo();
  }
}
Output
I am a Driver.
I am Driving a Truck.

In the above program, the sub class TruckDriver overrides the getInfo() method of superclass Driver. Inside getInfo() method of TruckDriver class, we used super.getInfo() to call getInfo() method of the super class Driver.


Best Practices and Considerations for Method Overriding

  • Follow the Liskov Substitution Principle : Method overriding should adhere to the Liskov Substitution Principle, which states that objects of a superclass should be replaceable with objects of a subclass without affecting the correctness of the program. This implies that the overriding method in the subclass should not violate the contract established by the overridden method in the superclass.

  • Document the Behavior : Document the intended behavior of the overridden method, especially if it provides a specific implementation different from the default behavior in the superclass. This documentation guides users and maintainers of the code.
    class Animal {
        /**
         * Produces the sound of the animal.
         */
        void makeSound() {
            System.out.println("Generic animal sound");
        }
    }
    
    class Cat extends Animal {
        /**
         * Produces the sound of a cat.
         */
        @Override
        void makeSound() {
            System.out.println("Meow");
        }
    }
    

  • Be careful with super : When overriding a method, be cautious when using the super keyword to invoke the overridden method in the superclass. Using super allows you to access the functionality of the superclass while providing additional or modified behavior in the subclass.
    class Animal {
        void makeSound() {
            System.out.println("Generic animal sound");
        }
    }
    
    class Cat extends Animal {
        @Override
        void makeSound() {
        // Call the overridden method in the superclass
            super.makeSound(); 
            System.out.println("Meow");
        }
    }
    

  • Be Mindful of final Methods : If a method in the superclass is marked as final, it cannot be overridden in any subclass. Attempting to do so will result in a compilation error. final methods are considered complete and should not be altered in subclasses.
    class Superclass {
        final void finalMethod() {
            // Implementation
        }
    }
    
    class Subclass extends Superclass {
        // Compilation error: cannot override final method
        @Override
        void finalMethod() {
            // New implementation
        }
    }
    

  • Know the Difference Between Method Overloading and Overriding : Method overloading (having multiple methods with the same name in the same class) is different from method overriding. Overloading is based on having different parameter lists, while overriding is about providing a specific implementation for a method that is already defined in a superclass.
    class Example {
        // Method overloading
        void display(int x) {
            System.out.println("Displaying integer: " + x);
        }
    
        void display(double y) {
            System.out.println("Displaying double: " + y);
        }
    
        // Method overriding
        void performAction() {
            // Implementation in the subclass
        }
    }
    


Conclusion

Method overriding is a fundamental concept in Java that facilitates the creation of flexible and extensible object-oriented designs. By allowing a subclass to provide a specific implementation for a method in its superclass, Java supports polymorphism and code reuse. Understanding the syntax, use cases, and best practices of method overriding empowers developers to create robust and maintainable code. Whether customizing behavior, achieving polymorphism, or extending frameworks, method overriding is a valuable tool in the Java developer's toolkit.