Method hiding in Java is a concept that applies specifically to static methods in an inheritance hierarchy.
It occurs when a subclass defines a static method with the exact same signature (name and parameters) as a static method in its superclass. In this case, the subclass's method is said to "hide" the superclass's method, rather than "override" it.
This is a critical distinction because static methods belong to the class itself, not to an instance of the class. The decision of which method to call is made at compile-time based on the reference type of the variable, not the object type at runtime.
Method hiding vs. method overriding
Understanding method hiding is easier by contrasting it with method overriding, which applies to non-static (instance) methods.
| Characteristic | Method Hiding | Method Overriding |
|---|---|---|
| Method type | Involves only static methods. | Involves only instance methods. |
| Binding time | Resolved at compile-time based on the reference type. | Resolved at runtime based on the actual object type. |
| Polymorphism | Does not exhibit polymorphic behavior. The method called is determined statically. | Exhibits runtime polymorphism. The specific method executed is determined dynamically. |
| Key behavior | A superclass reference holding a subclass object will always call the superclass's hidden method. | A superclass reference holding a subclass object will call the subclass's overridden method. |
Rules for method hiding
For a method in a subclass to hide a method in its superclass, several rules must be followed:
- Matching signature: The method in the subclass must have the exact same signature (name and parameter list) as the method in the superclass.
- Static to static: Both the superclass and subclass methods must be
static. If one isstaticand the other is an instance method, it is a compile-time error. - Access modifier: The hiding method in the subclass must be at least as accessible as the hidden method in the superclass. For example, a
publicmethod in the superclass cannot be hidden by aprivatemethod in the subclass. - Return type: The return type must be the same, or a covariant type (a subclass of the superclass method's return type).
Example of method hiding
class Animal {
public static void printMessage() {
System.out.println("Static method in Animal class");
}
}
class Cat extends Animal {
// This method HIDES the static method in the Animal class
public static void printMessage() {
System.out.println("Static method in Cat class");
}
}
public class Main {
public static void main(String[] args) {
// Accessing via class names is the recommended approach for static methods
Animal.printMessage(); // Prints: Static method in Animal class
Cat.printMessage(); // Prints: Static method in Cat class
// Demonstrating the compile-time binding
Animal animalRef = new Cat(); // An Animal reference to a Cat object
animalRef.printMessage(); // Prints: Static method in Animal class
// Demonstrating method overriding for comparison
animalRef.instanceMethod(); // Assuming an instance method exists, this would call Cat's version.
}
}
Use code with caution.
In this example, even though animalRef holds a Cat object, the call to animalRef.printMessage() executes the Animal class's static method. This is because the compiler uses the reference type (Animal) to resolve the method call at compile-time. The Cat class's printMessage method has effectively hidden the Animal class's version.
Key insights and best practices
Calling a hidden method
Even after a method is hidden, you can still access the superclass's version by explicitly using the superclass's name.
// Continuing from the example above
class Main {
public static void main(String[] args) {
// You can still call the original hidden method
Animal.printMessage();
}
}
Use code with caution.
Avoiding confusion
Method hiding can lead to confusing and hard-to-diagnose bugs if developers mistake it for method overriding. To prevent this, developers should:
- Avoid hiding static methods: In most cases, it's a code smell that indicates a design flaw. The best practice is to avoid giving subclasses a static method with the same signature as a superclass.
- Use the class name for static method calls: Always invoke a static method with the class name (
ClassName.method()) rather than through an object reference (object.method()). This makes the intent clear and prevents confusion. - Utilize static code analysis tools: Some tools can detect and warn about method hiding, helping to catch potential issues early.
Why are static methods not "overridden"?
The fundamental reason static methods cannot be overridden lies in their nature and how they are handled by the Java Virtual Machine (JVM).
- No object instance needed: Static methods are associated with the class, not with any specific instance. Overriding, and its runtime polymorphism, depends on having an object instance to determine which version of the method to call.
- Compile-time binding: Static methods are bound at compile time, while overridden methods are resolved at runtime. This means the compiler decides which static method to call by looking at the reference type, ignoring the object's actual type.
- Conflicting principles: The concept of a "static" (not dynamic, tied to the class) and "overriding" (dynamic, tied to the object) are contradictory.