Monday, December 8, 2025

Java Method Overriding: 3 Counter-Intuitive Rules You Need to Know

 

Introduction

Method overriding in Java seems straightforward at first glance. You have a method in a parent class, and you create a more specific version in a child class. Simple, right? But lurking beneath this simple definition are hidden complexities and "gotcha" rules that can easily trip up even experienced developers.

This post will distill the most surprising and impactful rules of method overriding. We won't just cover what the rules are; we'll explore the crucial why behind them, giving you a deeper, more practical understanding of how Java's object-oriented system is designed for stability and predictability.

--------------------------------------------------------------------------------

The Takeaways

1. The Golden Rule: Don't Break Your Promises to the Outside World

When overriding a method, the access modifier in the child class cannot be more restrictive than in the parent class. You can only keep the scope the same or increase it (e.g., from default to public), but you can never reduce it (e.g., from public to default).

The core rationale for this rule is to maintain a stable contract with other parts of your code that use the method. Imagine hundreds of pieces of code across your application rely on a public parent method. If a child class could override that method and make it default, all that external code would suddenly break because it would no longer have access. The rule prevents this chaos.

without overriding this method accessed by several outside people after overriding this method also should be accessed by same set of people... the people who are already accessing they should not be affected.

2. The Exception Rule: You Can't Throw New Problems at Your Callers

If a child's overriding method throws a checked exception, the parent's method must declare that it throws the same checked exception or a parent of that exception. A child method cannot introduce a completely new, undeclared checked exception.

This rule connects directly back to the principle of not breaking contracts. Code that calls the parent method is only prepared to try...catch the specific checked exceptions declared in the parent's method signature. The caller has a try-catch block designed for the parent's declared exceptions; forcing it to handle a new, unexpected checked exception from a child would break its compile-time safety contract.

It's important to note that this strict rule does not apply to unchecked exceptions (like RuntimeException and its children), as "there are no restrictions for unchecked exceptions".

if a child class method throws any checked exception compulsory parent class method should throw the same checked exception or its parent.

3. The Biggest Twist: Static Methods Can't Be Overridden

This is perhaps the most surprising rule: static methods cannot be overridden. Attempting to override a static method with a non-static one, or vice-versa, will result in a compile-time error.

So what happens if both the parent and child class methods are static? The code will compile without error, but this is not method overriding. The correct term for this behavior is Method Hiding.

The critical difference lies in how the method call is resolved:

  • Overriding (for non-static methods): Method resolution is handled by the JVM at runtime, based on the actual object's type. This is runtime polymorphism.
  • Method Hiding (for static methods): Method resolution is handled by the compiler at compile-time, based on the reference variable's type. This is compile-time polymorphism.

Consider the code parent p1 = new child(); p1.M1();. If M1 is a non-static method, overriding ensures the child's version is called. However, if M1 is a static method (method hiding), the parent's version is called because the compiler only sees the parent reference type.

To understand why the resolution behaves this way, the source offers a powerful analogy. Think of overriding as erasing something from a whiteboard and writing new data—the old data is truly gone. In contrast, think of method hiding as pinning a new chart over an old one. The new chart hides the old one, but both still exist. If you use a reference to the "new chart" (the child type), you see it. If you use a reference to the "old chart" (the parent type), you see that one instead.

it seems overriding concept applicable for static methods but it is not overriding and it is Method hiding.

--------------------------------------------------------------------------------

Conclusion

These rules, while sometimes complex, are not arbitrary. They are carefully designed to create predictable, stable, and less error-prone object-oriented systems. By enforcing clear contracts regarding access, exceptions, and method resolution, Java ensures that polymorphism works as intended without causing unexpected side effects in unrelated parts of an application.

Knowing that static methods are resolved by reference type at compile-time, how might this change your approach to designing and using utility classes in your projects?

No comments:

Post a Comment

Featured Post

Java Method Overriding: 3 Counter-Intuitive Rules You Need to Know

  Introduction Method overriding in Java seems straightforward at first glance. You have a method in a parent class, and you create a more s...

Popular Posts