1. Introduction
Method overriding occurs when a subclass provides its own specific implementation of a method that is already defined in its superclass, using the same method signature. It is the foundation of runtime (dynamic) polymorphism in Java.
Cricket analogy: A junior batter inheriting the "batting style" from a senior mentor but developing their own signature shot with the exact same stroke name is like a subclass overriding a method, same signature, own implementation, enabling runtime polymorphism.
Overriding lets a subclass customize or extend inherited behavior while still being usable wherever the superclass type is expected.
Cricket analogy: A specialist finisher can still be selected under the general "batter" role in the team sheet while bringing their own customized late-innings hitting style, like an overridden method still usable wherever the superclass type is expected.
2. Syntax
class Animal {
void makeSound() {
System.out.println("Some generic animal sound");
}
}
class Dog extends Animal {
@Override
void makeSound() {
System.out.println("Bark");
}
}3. Explanation
To override a method, the subclass method must have the exact same name and parameter list (signature) as the superclass method, and a compatible return type — either identical or a covariant return type (a subtype of the original return type).
Cricket analogy: To officially replace a bowler in the same over, the substitute must bowl the same type of delivery under the same over rules and deliver an outcome the umpire accepts as equivalent, like overriding requiring the same signature and a compatible return type.
Unlike overloading, overriding is resolved at runtime based on the actual object type (dynamic binding / late binding), not the reference variable's declared type. This is why Animal a = new Dog(); a.makeSound(); prints "Bark" — the JVM looks at the real object (Dog) at runtime.
Cricket analogy: Even if the scorecard lists a player under their general "all-rounder" designation, at the crease it's their actual specialized skill, say express pace, that determines what really happens, like Animal a = new Dog() resolving to Dog's actual behavior at runtime.
The @Override annotation is optional but strongly recommended: it tells the compiler to verify that the method actually overrides a superclass method, catching typos in the signature at compile time instead of silently creating an unrelated overloaded method.
Cricket analogy: Declaring "I'm taking over as strike bowler" formally with the captain lets everyone verify you actually match the required over slot instead of accidentally bowling an unscheduled extra over, like @Override catching a signature typo at compile time.
The overriding method's access modifier cannot be more restrictive than the overridden method's. For example, a public method in the superclass cannot be overridden as protected or private in the subclass.
Cricket analogy: A vice-captain's public authority to make bowling changes cannot be quietly narrowed to a private, personal decision when they step into the captain's role, just as an overriding method can't reduce a public superclass method's access to protected or private.
Exam tip: static methods, final methods, and private methods cannot be overridden. A static method with the same signature in a subclass is called 'method hiding', not overriding, and is resolved using the reference type, not the object type.
If you accidentally change the parameter list while trying to override a method, you create a new overload instead of an override — the @Override annotation prevents this mistake by failing to compile.
4. Example
class Animal {
void makeSound() {
System.out.println("Some 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 Main {
public static void main(String[] args) {
Animal a1 = new Dog();
Animal a2 = new Cat();
a1.makeSound();
a2.makeSound();
}
}5. Output
Bark
Meow6. Key Takeaways
- Overriding means a subclass redefines a superclass method with the same signature.
- Overriding is resolved at runtime based on the actual object type (dynamic binding).
- Covariant return types are allowed; access modifiers cannot become more restrictive.
- static, final, and private methods cannot be overridden.
- @Override annotation helps the compiler catch signature mistakes.
Practice what you learned
1. What determines which overridden method is executed at runtime?
2. Which of these cannot be overridden?
3. Can an overriding method have a more restrictive access modifier than the overridden method?
4. What is the purpose of the @Override annotation?
5. A subclass redefines a static method with the same signature as its superclass. What is this called?
Was this page helpful?
You May Also Like
Method Overloading in Java
Learn how Java resolves method overloading through parameter lists at compile time, and why return type alone cannot distinguish overloaded methods.
super Keyword in Java
Learn how the Java super keyword lets a subclass access parent class fields, methods, and constructors that are shadowed or overridden.
Polymorphism in Java
Explore compile-time and runtime polymorphism in Java, including method overloading, overriding, and dynamic dispatch.
Related Reading
Related Study Notes in Programming
Browse all study notesApache Spark Study Notes
Programming · 30 topics
ProgrammingApache Flink Study Notes
Programming · 30 topics
ProgrammingHadoop Study Notes
Programming · 30 topics
ProgrammingSnowflake Study Notes
Programming · 30 topics
ProgrammingApache Airflow Study Notes
Programming · 30 topics
Programmingdbt (Data Build Tool) Study Notes
Programming · 30 topics