This rule flags cases where a derived class defines a static method with the same signature (name and parameters) as a static method in its base class.
Method hiding occurs when a subclass defines a class-level method that has the same signature as a class-level method in its superclass. This is fundamentally different from method overriding, which applies to instance-level methods.
With instance-level methods, languages typically use polymorphism: the method called is determined by the actual runtime type of the object. This allows for dynamic behavior based on the object’s true type.
With class-level methods, however, languages use static binding: the method called is determined by the declared type of the reference at compile time, not the actual type of the object. This means that even if you have a superclass reference pointing to a subclass object, calling a class-level method will invoke the superclass version, not the subclass version.
This behavior is counterintuitive and contradicts developers' expectations based on how instance-level methods work. When reading code, developers naturally expect polymorphic behavior, but method hiding violates this expectation.
Consider this example pattern:
A parent class defines a class-level method that prints "Parent". A child class defines a class-level method with the same signature that prints "Child". When a variable is declared as the parent type but holds a child instance, calling the method through that variable prints "Parent", not "Child".
Even though the variable refers to a child instance, the parent’s method is called because the variable is declared as the parent type. This is confusing because instance-level methods would exhibit polymorphic behavior in the same situation.
The confusion is amplified when:
In Java, this looks like:
class Parent {
static void display() {
System.out.println("Parent");
}
}
class Child extends Parent {
static void display() { // Hides Parent.display()
System.out.println("Child");
}
}
Parent obj = new Child();
obj.display(); // Prints "Parent", not "Child"!
Method hiding makes code harder to understand and maintain. Developers might incorrectly assume that method calls will be resolved at runtime based on the actual object type (dynamic dispatch), leading to logic errors that are difficult to diagnose. During refactoring, changing variable types can silently change which method is called, introducing subtle bugs. The code becomes less intuitive and requires deeper knowledge of compile-time method binding rules to understand correctly.
The simplest solution is to rename the static method in the subclass to avoid hiding. This makes the code’s intent clear and eliminates confusion about which method will be called.
class Parent {
static void calculate() {
// Parent implementation
}
}
class Child extends Parent {
static void calculate() { // Noncompliant
// Child implementation
}
}
class Parent {
static void calculate() {
// Parent implementation
}
}
class Child extends Parent {
static void calculateExtended() {
// Child implementation
}
}