What’s New ?

The Top 10 favtutor Features You Might Have Overlooked

Read More

Overriding in Java (Methods, Uses, Examples)

  • Nov 16, 2023
  • 10 Minutes Read
  • Why Trust Us
    We uphold a strict editorial policy that emphasizes factual accuracy, relevance, and impartiality. Our content is crafted by top technical writers with deep knowledge in the fields of computer science and data science, ensuring each piece is meticulously reviewed by a team of seasoned editors to guarantee compliance with the highest standards in educational content creation and publishing.
  • By Nihal Mahansaria
Overriding in Java (Methods, Uses, Examples)

Method overriding serves as a foundation in object-oriented programming for achieving polymorphism, a fundamental principle that permits different classes to be treated as instances of the seme class via a common interface. Particularly, subclasses of method overriders are able to provide their own implementation of a method that was declared in the superclass.  In this article, we will learn the concept of Method overriding along with examples.

Overview of Method Overriding

Method overriding establishes a clear link between a superclass and it's subclasses. When a subclass inherits a method from its superclass, it can redefine the method to suit its specific needs. This enables the creation of a more specialized behavior without modifying the superclass, adhering to the open-closed principle of object-oriented design. In Java, method overriding is tightly connected to inheritance and is vital for achieving dynamic polymorphism.

Rules and Conditions for Method Overriding

Rules to Follow:

  • Method Signature Matching: The overriding method in the subclass must have the seme method signature as the overridden method in the superclass. This includes the method name, parameters, and return type.
  • Covariant Return Types: Java allows the return type of the overriding method to be a subtype of the overridden method. This is known as covariant return types.
  • Access Modifiers: The access modifier of the overriding method can't be more restrictive than the overridden method. For example, if the overridden method is public, the overriding method cannot be private.
  • Exception Handling: The overriding method can't throw checked exceptions broader than the ones thrown by the overridden method.

Example:

class Animal {
    void makeSound() {
        System.out.println("Some generic sound");
    }
}

class Dog extends Animal {
    @Override
    void makeSound() {
        System.out.println("Bark");
    }
}

 

In this example, the Dog class adheres to the rules of method overriding by matching the signature of the makeSound method in the Animal class.

@Override Annotation

The @Override annotation is a valuable tool provided by Java to explicitly indicate that a method in a subclass is intended to override a method in its superclass. While not mandatory, using this annotation helps catch errors at compile-time if the annotated method does not correctly override a method in the superclass.

Example:

class Animal {
    void eat() {
        System.out.println("Animal is eating");
    }
}

class Dog extends Animal {
    @Override
    void eat() {
        System.out.println("Dog is eating");
    }
}

 

By adding @Override before the eat method in the Dog class, developers can ensure that they are correctly overriding the eat method from the Animal class.

Examples of Method Overriding

Let’s look at some examples of Method Overriding.

Example 1:

class Shape {
    void draw() {
        System.out.println("Drawing a shape");
    }
}

class Circle extends Shape {
    @Override
    void draw() {
        System.out.println("Drawing a circle");
    }
}

 

In this example, the Circle class provides a specific implementation of the draw method, tailored for drawing circles, which overrides the more general implementation in the Shape class.

Example 2:

class Vehicle {
    void start() {
        System.out.println("Vehicle is starting");
    }
}

class Car extends Vehicle {
    @Override
    void start() {
        System.out.println("Car is starting");
    }
}

 

Here, the Car class overrides the start method of the Vehicle class, specifying the behavior for starting a car.

Use of Super Keyword in Method Overriding

The super keyword in Java plays a crucial role in method overriding. It allows the subclass to explicitly call the overridden method in the superclass, providing a way to extend or modify the behavior defined in the superclass.

Example:

class Animal {
    void makeSound() {
        System.out.println("Some generic sound");
    }
}

class Dog extends Animal {
    @Override
    void makeSound() {
        super.makeSound(); // invokes the makeSound method of the Animal class
        System.out.println("Bark");
    }
}

 

In this example, the super.makeSound() statement invokes the makeSound method from the Animal class before executing the Bark statement in the Dog class.

Covariant Return Types

Covariant return types, introduced in Java 5, allow a subclass to override a method with a return type that is a subtype of the return type in the superclass. This provides more flexibility and precision when designing class hierarchies.

Example:

class Animal {
    Animal reproduce() {
        return new Animal();
    }
}

class Dog extends Animal {
    @Override
    Dog reproduce() {
        return new Dog();
    }
}

 

Here, the Dog class overrides the reproduce method with a more specific return type, indicating the birth of a new dog.

Pitfalls and Common Mistakes

One common mistake in method overriding is forgetting to use the @Override annotation when intending to override a method. This omission can lead to unintentional method creation instead of overriding.

class Bird {
    void sing() {
        System.out.println("Bird is singing");
    }
}

class Sparrow extends Bird {
    // Forgot @Override here
    void sing() {
        System.out.println("Sparrow is singing");
    }
}

 

Adding @Override before the sing method in the Sparrow class would catch the error at compile-time, ensuring the method is intended for overriding.

What is Dynamic Method Dispatch?

Dynamic Method Dispatch is a critical concept in method overriding, facilitating the selection of the appropriate version of the overridden method at runtime based on the actual type of the object.

Example:

class Animal {
    void makeSound() {
        System.out.println("Some generic sound");
    }
}

class Dog extends Animal {
    @Override
    void makeSound() {
        System.out.println("Bark");
    }
}

public class Main {
    public static void main(String[] args) {
        Animal myDog = new Dog();
        myDog.makeSound(); // Outputs "Bark"
    }
}

  

In this example, the makeSound method of the Dog class is called even though the reference is of type Animal, showcasing the power of dynamic method dispatch.

Best Practices for Method Overriding

  • Use @Override annotation: Always use the @Override annotation when intending to override a method. It helps catch errors at compile-time and ensures that the method is correctly overridden.
  • Follow naming conventions: Maintain consistency and meaningful method names to enhance code readability. This is especially crucial when working with large codebases or collaborating with other  developers.
  • Understand the purpose of the overridden method: Before overriding a method, thoroughly understand its purpose in the superclass. Ensure that the overridden method in the subclass server the seme purpose or behavior, adhering to the principle of least astonishment.

Use Cases and Real-world Examples

Java's java.util.ArrayList class provides a practical application of method overriding. The equals method is overridden to enable meaningful comparison of lists.

ArrayList<String> list1 = new ArrayList<>();

ArrayList<String> list2 = new ArrayList<>();

boolean isEqual = list1.equals(list2); // Calls the overridden equals method for meaningful list comparison

 

In this scenario, the overridden equals method in ArrayList ensures that the contents of the lists are compared, offering a more meaningful comparison for the specific context of lists.

Conclusion

Method overriding in Java is a powerful mechanism that promotes code reusability and flexibility. By understanding the rules, best practices, and nuances of method overriding, developers can create robust and maintainable object-oriented systems. From the fundamental principles of inheritance to the intricacies of dynamic method dispatch, method overriding empowers developers to craft sophisticated and extensible code. 

FavTutor - 24x7 Live Coding Help from Expert Tutors!

About The Author
Nihal Mahansaria
As a computer science student with a passion for technology and a drive to learn, I have developed a diverse set of skills in web development, machine learning, and technical content writing. With experience in multiple front-end and back-end frameworks, including Flask and Python, I am able to create scalable and efficient web applications.