Method overriding is a core concept of Object-Oriented Programming in Java. It allows a child class to provide its own implementation of a method that it inherits from a parent class or receives through an interface contract.
Overriding is especially important because it enables runtime polymorphism. A parent class or interface reference can point to a child object, and when an overridden instance method is called, Java can execute the implementation belonging to the actual object.
Core idea: Method overriding means a child class provides a specialized implementation of an inherited instance method while preserving the same method signature.
Why Do We Need Method Overriding?
Imagine a parent class called Animal. Every animal can make a sound, but different animals make different sounds.
The parent class can define the general operation, while each child class can customize the behavior.
class Animal { void sound() { System.out.println("Animal makes a sound"); } } class Dog extends Animal { @Override void sound() { System.out.println("Dog barks"); } } class Cat extends Animal { @Override void sound() { System.out.println("Cat meows"); } }
The parent class provides the general behavior, but Dog and Cat replace that behavior with their own implementations.
Basic Method Overriding Example
class Vehicle { void start() { System.out.println("Vehicle starts"); } } class Car extends Vehicle { @Override void start() { System.out.println("Car starts"); } } public class Main { public static void main(String[] args) { Car car = new Car(); car.start(); } }
The Car class inherits start() from Vehicle, but it provides its own implementation. Therefore, calling car.start() executes the Car version.
Rules for Method Overriding
Method overriding follows specific rules. Understanding these rules is essential because a small signature difference can change overriding into a completely different situation.
- The child class must inherit the method or otherwise implement the relevant interface method.
- The method name must be the same.
- The parameter list must match the inherited method.
- The return type must be the same or covariant for reference types.
- The overriding method cannot reduce the visibility of the inherited method.
- A checked exception declared by the overriding method cannot be broader than the checked exception allowed by the inherited method.
- Static methods are hidden, not overridden.
- Private methods are not overridden because they are not inherited by subclasses.
- A final method cannot be overridden.
Method Signature Must Match
For normal method overriding, the child method must have the same name and parameter types as the inherited method.
class Parent { void display(int value) { System.out.println("Parent"); } } class Child extends Parent { @Override void display(int value) { System.out.println("Child"); } }
The method name and parameter list match exactly, so the child method overrides the parent method.
Overloading Is Not Overriding
One of the most common beginner mistakes is confusing method overloading with method overriding.
class Parent { void show(int value) { System.out.println("Parent"); } } class Child extends Parent { void show(String value) { System.out.println("Child"); } }
The child method does not override show(int) because its parameter type is String. Instead, the child class has introduced a different overloaded method.
| Feature | Overloading | Overriding |
|---|---|---|
| Class relationship | Not required | Parent-child or interface relationship required |
| Method name | Same | Same |
| Parameters | Must be different | Must match |
| Binding | Compile time | Runtime for overridden instance methods |
| Purpose | Provide multiple parameter-based variations | Provide specialized inherited behavior |
Using the @Override Annotation
Java provides the @Override annotation to explicitly tell the compiler that a method is intended to override an inherited method.
class Parent { void display() { System.out.println("Parent display"); } } class Child extends Parent { @Override void display() { System.out.println("Child display"); } }
Using @Override is strongly recommended because the compiler can detect mistakes in the method signature.
For example, if you accidentally change the parameter type, the compiler can immediately report that the method does not actually override a parent method.
Best practice: Whenever you intentionally override a method, use @Override. It documents your intention and gives the compiler an opportunity to catch mistakes.
Return Type in Method Overriding
An overriding method can use the same return type as the inherited method. For reference types, Java also allows a more specific return type. This is called a covariant return type.
class Animal { } class Dog extends Animal { } class Parent { Animal getAnimal() { return new Animal(); } } class Child extends Parent { @Override Dog getAnimal() { return new Dog(); } }
The parent method returns Animal, while the child method returns Dog. Because Dog is a subtype of Animal, this is a valid covariant return type.
Access Modifiers in Method Overriding
An overriding method cannot have more restrictive access than the inherited method.
For example, if a parent method is public, the child method cannot make it protected or private.
class Parent { public void show() { System.out.println("Parent"); } } class Child extends Parent { @Override public void show() { System.out.println("Child"); } }
The child can keep the same visibility or make the method more accessible, but it cannot reduce accessibility.
Checked Exceptions and Overriding
When overriding a method, the child method has restrictions on checked exceptions. It cannot introduce a broader checked exception than the inherited method permits.
class Parent { void read() throws java.io.IOException { System.out.println("Reading data"); } } class Child extends Parent { @Override void read() throws java.io.FileNotFoundException { System.out.println("Reading file"); } }
This is valid because FileNotFoundException is a subclass of IOException.
The overriding method may also throw no checked exception at all, or it may throw an appropriate narrower checked exception.
Interview point: The restriction applies to checked exceptions. Unchecked exceptions do not have the same overriding restriction.
Using super with an Overridden Method
Sometimes the child class wants to extend the parent's behavior rather than completely replace it. Java provides the super keyword for this purpose.
class Vehicle { void start() { System.out.println("Vehicle starts"); } } class Car extends Vehicle { @Override void start() { super.start(); System.out.println("Car performs additional startup steps"); } }
The expression super.start() explicitly calls the parent implementation. The child can then add its own behavior.
Overriding and Runtime Polymorphism
Method overriding is the foundation of runtime polymorphism.
class Animal { void sound() { System.out.println("Animal sound"); } } class Dog extends Animal { @Override void sound() { System.out.println("Dog barks"); } } public class Main { public static void main(String[] args) { Animal animal = new Dog(); animal.sound(); } }
The compiler sees an Animal reference and confirms that sound() is available. At runtime, the actual object is a Dog, so the overridden Dog.sound() implementation executes.
Key connection: Overriding defines the specialized behavior; runtime polymorphism allows that specialized behavior to be selected through a common parent or interface reference.
Can Static Methods Be Overridden?
No. Static methods belong to the class rather than participating in normal runtime overriding. If a child class declares a static method with the same signature as a parent static method, the method is hidden, not overridden.
class Parent { static void show() { System.out.println("Parent"); } } class Child extends Parent { static void show() { System.out.println("Child"); } }
Calling a static method is resolved according to the class or reference context rather than using the same dynamic dispatch mechanism as overridden instance methods.
Can Private Methods Be Overridden?
No. Private methods are not inherited by subclasses, so a child class cannot override a parent's private method.
class Parent { private void show() { System.out.println("Parent private method"); } } class Child extends Parent { private void show() { System.out.println("Child private method"); } }
The child declaration is a separate method, not an override of the parent's private method.
Can Final Methods Be Overridden?
No. A method declared with final cannot be overridden by a subclass.
class Parent { final void display() { System.out.println("Fixed behavior"); } } class Child extends Parent { // void display() { } // Compile-time error }
The final modifier tells Java that subclasses are not allowed to replace that method implementation.
Overriding Interface Methods
A class can also provide an implementation for a method declared by an interface. This is commonly described as implementing or overriding the interface method.
interface Payment { void pay(); } class CardPayment implements Payment { @Override public void pay() { System.out.println("Payment completed using card"); } }
The CardPayment class fulfills the contract defined by Payment. Notice that the method must be public because interface methods that are implemented this way are public.
Common Beginner Mistakes
- Changing the parameter list and incorrectly calling the method an override.
- Trying to override a private, static, or final method.
- Reducing the access level of an inherited method.
- Returning an incompatible type from an overriding method.
- Forgetting the @Override annotation and accidentally creating a new method because of a signature mistake.
- Confusing super.method() with normal dynamic dispatch.
Best Practices
- Use @Override whenever you override a method.
- Keep the child implementation consistent with the behavioral contract of the parent or interface.
- Use super when the parent behavior should be preserved and extended.
- Avoid overriding methods simply to change behavior in ways that violate what callers expect from the parent type.
- Use clear inheritance hierarchies where the child genuinely represents a specialized form of the parent.
Interview Insights
A common interview question is: "What is method overriding?" A strong answer is: Method overriding occurs when a subclass provides its own implementation of an inherited instance method using the same method signature, enabling specialized behavior and runtime polymorphism.
Another frequent question is: "Can we override static, private, or final methods?" The answer is no in the normal overriding sense. Static methods are hidden, private methods are not inherited, and final methods cannot be overridden.
Interviewers may also ask why @Override is useful. The best answer is that it makes the programmer's intent explicit and lets the compiler verify that the method actually overrides an inherited method.
Final Takeaway
Method overriding allows child classes to specialize inherited behavior while maintaining a common method contract. The method name and parameter list must match, the return type must be compatible, and the overriding method cannot reduce visibility. Most importantly, overriding is the mechanism that makes runtime polymorphism possible: a common reference can point to different objects, and each object can provide its own implementation of the same operation.
