Java Notes
Complete guide to method overriding in Java — runtime polymorphism, @Override annotation, covariant return types, rules and restrictions, and dynamic method dispatch.
Method overriding occurs when a subclass provides its own implementation of a method that is already defined in its parent class. The method in the child class must have the same name, same parameters, and same (or covariant) return type as the parent method.
This is runtime polymorphism (dynamic polymorphism) — the JVM decides which method to call based on the actual object type at runtime, not the reference type.
Why Overriding Matters
public class Animal {
public void makeSound() {
System.out.println("Some generic animal sound");
}
public void eat() {
System.out.println("Animal is eating");
}
}
public class Dog extends Animal {
@Override
public void makeSound() {
System.out.println("Woof! Woof!");
}
// eat() is NOT overridden — inherited as-is
}
public class Cat extends Animal {
@Override
public void makeSound() {
System.out.println("Meow!");
}
}
public class Snake extends Animal {
@Override
public void makeSound() {
System.out.println("Hssss!");
}
}
public class Main {
public static void main(String[] args) {
// The POWER of overriding: write code that works with ANY animal
Animal[] zoo = { new Dog(), new Cat(), new Snake(), new Dog() };
for (Animal animal : zoo) {
animal.makeSound(); // Each calls ITS OWN version!
}
}
}Woof! Woof! Meow! Hssss! Woof! Woof!
Without overriding, every animal would say "Some generic animal sound." With overriding, each animal has its own behavior while sharing the same interface.
Rules for Valid Overriding
| Rule | Explanation |
|---|---|
| Same method name | Must match exactly |
| Same parameters | Same number, type, and order |
| Same or covariant return type | Can return a subtype |
| Access: same or wider | protected → public ✅, public → private ❌ |
Cannot override final methods | final prevents overriding |
Cannot override static methods | Static methods are hidden, not overridden |
Cannot override private methods | Private methods aren't visible to subclass |
| Can throw same or fewer checked exceptions | Cannot add new checked exceptions |
The @Override Annotation
Always use @Override — it tells the compiler to verify you're actually overriding:
public class Shape {
public double area() {
return 0;
}
}
public class Circle extends Shape {
private double radius;
public Circle(double radius) {
this.radius = radius;
}
@Override // Compiler checks that area() exists in parent
public double area() {
return Math.PI * radius * radius;
}
// @Override
// public double Area() { // ❌ Compile error! No 'Area()' in parent (typo)
// }
}Without @Override, a typo like Area() creates a NEW method instead of overriding — a silent bug!
Dynamic Method Dispatch (Runtime Resolution)
The JVM uses the actual object type (not the reference type) to decide which method to call:
--- Credit Card --- Charging $99.99 to card ending in 4444 --- PayPal --- Sending $250.0 via PayPal to alice@email.com --- Crypto --- Transferring $1000.0 in crypto to 0x742d35...
Covariant Return Types
The overriding method can return a subtype of the parent's return type:
public class AnimalFactory {
public Animal create() {
return new Animal();
}
}
public class DogFactory extends AnimalFactory {
@Override
public Dog create() { // Returns Dog (subtype of Animal) — VALID!
return new Dog();
}
}// Practical example
public class Builder {
public Builder setName(String name) { return this; }
}
public class AdvancedBuilder extends Builder {
@Override
public AdvancedBuilder setName(String name) { // Covariant return
super.setName(name);
return this; // Returns more specific type
}
public AdvancedBuilder setColor(String color) {
return this;
}
}Access Modifier Rules
You can make the overriding method MORE accessible, never less:
public class Parent {
protected void display() {
System.out.println("Parent display");
}
}
public class ChildValid extends Parent {
@Override
public void display() { // ✅ protected → public (wider access)
System.out.println("Child display - public");
}
}
public class ChildInvalid extends Parent {
// @Override
// private void display() { // ❌ COMPILE ERROR: protected → private (narrower)
// }
}Why? If parent promises protected access, child can't restrict it — that would break the substitution principle (code using Parent reference expects at least protected access).
Calling Parent's Overridden Method with super
[14:30:00.123] Application started → Written to app.log [14:30:00.124] User logged in → Written to app.log
What Cannot Be Overridden
public class Parent {
// 1. final methods - cannot override
public final void criticalMethod() {
System.out.println("This is final — cannot change");
}
// 2. static methods - hidden, not overridden
public static void staticMethod() {
System.out.println("Parent static");
}
// 3. private methods - not visible to child
private void helper() {
System.out.println("Parent helper");
}
}
public class Child extends Parent {
// criticalMethod() — Cannot override! Compile error with @Override
// This is METHOD HIDING, not overriding!
public static void staticMethod() {
System.out.println("Child static");
}
// This is a NEW method, not an override (parent's is private)
private void helper() {
System.out.println("Child helper — new method, not override");
}
}
public class Main {
public static void main(String[] args) {
Parent p = new Child();
p.staticMethod(); // "Parent static" — static uses REFERENCE type!
// Compare: if it were overriding, it would say "Child static"
}
}Parent static
Overloading vs Overriding — Complete Comparison
| Feature | Overloading | Overriding |
|---|---|---|
| Where | Same class | Subclass |
| Parameters | MUST differ | MUST be same |
| Return type | Can differ | Same or covariant |
| Binding | Compile-time (static) | Runtime (dynamic) |
| Access modifier | No restriction | Cannot narrow |
| Exceptions | No restriction | Cannot add checked |
static methods | Can overload | Cannot override (only hide) |
final methods | Can overload | Cannot override |
private methods | Can overload | Cannot override |
| Also called | Compile-time polymorphism | Runtime polymorphism |
Real-World Example: Shape Hierarchy
Blue Rectangle [Area: 15.00, Perimeter: 16.00] Red Circle [Area: 50.27, Perimeter: 25.13] Green Triangle [Area: 6.00, Perimeter: 12.00] Total area: 71.27
Common Mistakes
- Forgetting @Override and making a typo:
``java public void tostring() { } // ❌ Not overriding toString()! // @Override would catch this at compile time ``
- Trying to override with narrower access:
``java // Parent: public void show() @Override protected void show() { } // ❌ Compile error ``
- Confusing static method hiding with overriding:
``java Parent p = new Child(); p.staticMethod(); // Calls Parent's version! Not polymorphic. ``
- Not calling super when extending behavior:
``java @Override public void initialize() { // Forgot super.initialize() — parent setup skipped! doChildSetup(); } ``
- Throwing broader exceptions:
``java // Parent: void read() throws IOException @Override void read() throws Exception { } // ❌ Exception is broader than IOException ``
Best Practices
- Always use
@Overrideannotation — catches typos at compile time - Call
super.method()when you want to extend, not replace, behavior - Follow the Liskov Substitution Principle — child should be usable wherever parent is expected
- Don't override methods just to add logging — use AOP or decorators
- Keep the contract: if parent's Javadoc says "returns positive number," honor that
- Mark methods
finalif they shouldn't be overridden
Interview Questions
Q1: What is the difference between overloading and overriding? Overloading: same class, different params, compile-time binding. Overriding: subclass, same params, runtime binding.
Q2: Can we override a private method? No. Private methods aren't visible to subclasses. A same-named method in the child is a new method, not an override.
Q3: Can we override a static method? No. Static methods are hidden (not overridden). The method called depends on the reference type, not the object type.
Q4: What is covariant return type? An overriding method can return a subtype of the parent method's return type. e.g., parent returns Animal, child returns Dog.
Q5: Why can't we narrow the access modifier? It violates Liskov Substitution Principle. Code using a parent reference expects at least the parent's access level. Restricting it would break existing code.
Q6: What is dynamic method dispatch? The JVM mechanism that resolves overridden method calls at runtime based on the actual object type, not the reference type. This is how runtime polymorphism works.
Q7: Can we override a constructor? No. Constructors are not inherited, so they cannot be overridden. Each class defines its own constructors.
Q8: Can we override a method to make it synchronized? Yes. Adding synchronized to an overriding method is allowed because it doesn't violate the parent's contract. The child's method just adds thread-safety. However, removing synchronized from an overridden method can introduce concurrency bugs.
Q9: What are covariant return types in method overriding? Since Java 5, the overriding method can return a subtype of the parent method's return type. If parent returns Animal, child can return Dog. This is called covariant return types. It doesn't apply to primitives — only reference types.
Q10: What is the @Override annotation and why use it? @Override tells the compiler "I intend to override a parent method." If you misspell the method or get parameters wrong, the compiler gives an error instead of silently creating a new method. It's optional but strongly recommended for safety.
Q11: Can the overriding method throw broader exceptions? No. The overriding method can throw: (1) same exceptions as parent, (2) subclass of parent's exceptions, (3) no exception, or (4) any unchecked exception. It CANNOT throw broader checked exceptions — this would violate the parent's contract.
Q12: What is virtual method invocation in Java? In Java, all non-static, non-final, non-private methods are virtual by default. When you call a method on a parent reference pointing to a child object, the JVM uses the actual object type (not reference type) to determine which method to execute. This is dynamic dispatch.
Exam Focus
Revise definitions, diagrams, examples, and short-answer points for Method Overriding in Java.
Interview Use
Prepare one clear explanation, one practical example, and one common mistake for this Java Master Course topic.
Search Terms
java-master-course, java master course, java, master, course, oops, method, overriding
Related Java Master Course Topics