Method Overriding in Java – Rules and Examples
Method overriding happens when a subclass provides its own implementation of an instance method it inherits from a superclass or interface, using the same name, parameters and a compatible return type. When the method is called, the JVM runs the version belonging to the actual object. This is Java's runtime polymorphism.
This tutorial covers how overriding works, the @Override annotation, calling the parent version with super, every overriding rule (return types, access, exceptions), and why static, private and final methods cannot be overridden.
1. How Overriding Works
public class OverridingBasics {
static class Notification {
String channel() { return "generic"; }
void send(String msg) { System.out.println("[" + channel() + "] " + msg); }
}
static class EmailNotification extends Notification {
@Override String channel() { return "email"; } // overrides
}
static class SmsNotification extends Notification {
@Override String channel() { return "sms"; }
@Override void send(String msg) { // overrides and extends
String shortMsg = msg.length() > 20 ? msg.substring(0, 20) + "..." : msg;
super.send(shortMsg); // reuse the parent version
}
}
public static void main(String[] args) {
Notification[] all = { new Notification(), new EmailNotification(), new SmsNotification() };
for (Notification n : all) n.send("Your order #1042 has been shipped today");
}
}
[generic] Your order #1042 has been shipped today [email] Your order #1042 has been shipped today [sms] Your order #1042 has...
EmailNotificationoverrides onlychannel(); the inheritedsend()calls it and gets the email version.SmsNotificationoverridessend()and reuses the parent logic withsuper.send(...).- The array is typed
Notification[], yet each element behaves according to its real class. This is dynamic method dispatch.
2. Always Use @Override
@Override asks the compiler to confirm that the method really overrides something. Without it, a small mistake creates an overload instead, and the bug is silent:
public class OverrideAnnotation {
static class Point {
final int x, y;
Point(int x, int y) { this.x = x; this.y = y; }
// Mistake: parameter type is Point, not Object -> this OVERLOADS equals, it does not override it.
// Adding @Override here would make the compiler report the mistake.
public boolean equals(Point other) { return x == other.x && y == other.y; }
}
static class FixedPoint {
final int x, y;
FixedPoint(int x, int y) { this.x = x; this.y = y; }
@Override
public boolean equals(Object o) {
return o instanceof FixedPoint p && x == p.x && y == p.y;
}
@Override
public int hashCode() { return 31 * x + y; }
}
public static void main(String[] args) {
Object a = new Point(1, 2), b = new Point(1, 2);
System.out.println("Point equals (wrong overload): " + a.equals(b));
Object c = new FixedPoint(1, 2), d = new FixedPoint(1, 2);
System.out.println("FixedPoint equals (overridden): " + c.equals(d));
}
}
Point equals (wrong overload): false FixedPoint equals (overridden): true
With @Override on equals(Point), compilation would fail with "method does not override or implement a method from a supertype", pointing straight at the bug.
3. Rules of Method Overriding
| Rule | Details |
|---|---|
| Same signature | Same method name and same parameter types in the same order |
| Return type | Same type, or a subtype for reference types (covariant return); primitives must match exactly |
| Access modifier | Same or wider (protected → public is fine; public → protected is an error) |
| Checked exceptions | Same, narrower, fewer or none; never new or broader checked exceptions |
| Unchecked exceptions | Any, without restriction |
| Inheritance | Only inherited instance methods can be overridden (requires IS-A relationship) |
| Not overridable | static, private and final methods, and constructors |
import java.io.*;
public class OverridingRules {
static class Animal {
protected Animal reproduce() { return new Animal(); }
void load(String file) throws IOException { }
public String toString() { return "Animal"; }
}
static class Cat extends Animal {
// Covariant return type (Cat is a subtype of Animal) and wider access (protected -> public)
@Override public Cat reproduce() { return new Cat(); }
// May throw fewer or narrower checked exceptions (FileNotFoundException extends IOException)
@Override void load(String file) throws FileNotFoundException {
throw new FileNotFoundException(file + " not found");
}
public String toString() { return "Cat"; }
}
public static void main(String[] args) {
Animal a = new Cat();
System.out.println("reproduce() returned: " + a.reproduce());
try { a.load("cat.json"); }
catch (IOException e) { System.out.println("Caught: " + e); }
}
}
reproduce() returned: Cat Caught: java.io.FileNotFoundException: cat.json not found
4. Static, Private and Final Methods
Static methods are hidden, not overridden
A static method with the same signature in a subclass hides the parent's method. Which one runs depends on the reference type at compile time, not the object.
Private methods are not inherited
A method in the subclass with the same name as a parent's private method is a completely new method. Parent code calling its private method always gets its own version.
public class StaticHiding {
static class Parent {
static String info() { return "Parent.info (static)"; }
private String secret() { return "Parent.secret (private)"; }
String callSecret() { return secret(); }
}
static class Child extends Parent {
static String info() { return "Child.info (static)"; } // hides, not overrides
private String secret() { return "Child.secret (private)"; } // new method, not an override
}
public static void main(String[] args) {
Parent p = new Child();
System.out.println(Parent.info()); // static: resolved by type at compile time
System.out.println(Child.info());
System.out.println(p.callSecret()); // private: parent's version, no dynamic dispatch
}
}
Parent.info (static) Child.info (static) Parent.secret (private)
Final methods are locked
Declaring a method final prevents overriding; attempting it is a compile error ("overridden method is final"). See final keyword.
5. Calling the Parent Version with super
Inside an overriding method, super.methodName(...) calls the parent's implementation. This is the standard way to extend rather than replace behaviour, for example adding fields to toString() or extra checks before saving. See super keyword.
6. Overriding Object Methods
Every class inherits from Object, and these methods are commonly overridden:
toString(): a readable description of the object.equals(Object)andhashCode(): value equality; always override them together so objects work correctly inHashMapandHashSet.clone(): rarely; copy constructors are usually preferred.
Records generate correct equals, hashCode and toString automatically.
7. Best Practices
- Annotate every override with
@Override. - Honour the parent's contract (Liskov substitution principle): an override must work wherever the parent is expected.
- Do not call overridable methods from constructors; the subclass override may run before the subclass's fields are initialised.
- Make methods
final, or classes final or sealed, when subclasses must not change behaviour.
8. Summary
- Overriding replaces an inherited instance method with a subclass version; the object's class decides which runs.
- Same name and parameters; covariant return types allowed; access can only widen; checked exceptions can only narrow.
- Static methods are hidden, private methods are not inherited, and final methods cannot be overridden.
- Use
@Overrideandsuper.method()to write safe, extendable overrides.
Related Tutorials
Frequently Asked Questions (FAQ)
Q1. What is method overriding in Java?
Providing a new implementation of an inherited instance method in a subclass, with the same signature, so that calls on subclass objects run the new version.
Q2. Can we override a static method?
No. A static method with the same signature in a subclass hides the parent's method; the version called depends on the reference type, not the object.
Q3. Can we override a private method?
No. Private methods are not inherited, so a same-named subclass method is unrelated to the parent's.
Q4. Can we override a final method?
No. The compiler reports "overridden method is final".
Q5. Can we override a constructor?
No. Constructors are not inherited. They can be overloaded and can call the parent constructor with super(...).
Q6. Is @Override mandatory?
No, but strongly recommended. It makes the compiler verify that the method actually overrides something, catching signature mistakes.
Q7. What is a covariant return type?
An overriding method may return a subtype of the parent method's return type, for example Cat reproduce() overriding Animal reproduce().
Q8. Can an overriding method reduce visibility?
No. It can keep or widen access, but making a public method protected or private causes a compile error.
Q9. What exceptions can an overriding method throw?
Any unchecked exceptions, and only the same, narrower or fewer checked exceptions than the overridden method declares.
Q10. How do I call the parent's overridden method?
Use super.methodName(args) inside the subclass.
Q11. Can we override the main method?
No, because it is static. A subclass can declare its own main, which hides the parent's.
Q12. Can an abstract method be overridden?
It must be. Concrete subclasses override (implement) all inherited abstract methods.
Q13. Can a subclass override a method with a different parameter type?
No. Different parameter types create an overload, not an override.
Q14. Why should equals and hashCode be overridden together?
Equal objects must have equal hash codes. Overriding only equals breaks HashMap and HashSet, which use hashCode to find buckets.
Q15. Can a synchronized method be overridden by a non-synchronized one?
Yes. synchronized is not part of the signature, so the override decides for itself.
Q16. Can an interface's default method be overridden?
Yes. Implementing classes and sub-interfaces can override default methods.
Q17. What is the Liskov substitution principle?
Objects of a subclass should be usable wherever the parent type is expected without breaking correctness, so overrides must keep the parent method's contract.
Q18. Is overriding resolved at compile time or run time?
At run time. The compiler checks that the method exists on the reference type; the JVM chooses the implementation from the object's class.
Q19. Can a package-private method be overridden from another package?
No. Package-private methods are only inherited by subclasses in the same package; a subclass elsewhere declares an unrelated method.
Q20. Why is calling an overridable method from a constructor risky?
The subclass override runs before the subclass constructor has initialised its fields, so it may see default values such as null or 0.