When a class declares a static method m, the declaration of m hides any method m', where the signature of m is a subsignature of the signature of m' and the declaration of m' is both in the superclasses and superinterfaces of the declaring class and also would otherwise be accessible to code in the declaring class (The Java Language Specification, §8.4.8.2 "Hiding (by Class Methods)" [JLS 2005]).
...
In this noncompliant example, the programmer hides the static method rather than overriding it. Consequently, the code invokes the displayAccountStatus()
method of the superclass at two different call sites instead of invoking the superclass method at one call site and the subclass method at the other.
Code Block | ||
---|---|---|
| ||
class GrantAccess {
public static void displayAccountStatus() {
System.out.println("Account details for admin: XX");
}
}
class GrantUserAccess extends GrantAccess {
public static void displayAccountStatus() {
System.out.println("Account details for user: XX");
}
}
public class StatMethod {
public static void choose(String username) {
GrantAccess admin = new GrantAccess();
GrantAccess user = new GrantUserAccess();
if (username.equals("admin")) {
admin.displayAccountStatus();
} else {
user.displayAccountStatus();
}
}
public static void main(String[] args) {
choose("user");
}
}
|
...
In this compliant solution, the programmer declares the displayAccountStatus()
methods as instance methods , by removing the static
keyword. Consequently, the dynamic dispatch at the call sites produces the expected result. The @Override
annotation indicates intentional overriding of the parent method.
Code Block | ||
---|---|---|
| ||
class GrantAccess {
public void displayAccountStatus() {
System.out.print("Account details for admin: XX");
}
}
class GrantUserAccess extends GrantAccess {
@Override
public void displayAccountStatus() {
System.out.print("Account details for user: XX");
}
}
public class StatMethod {
public static void choose(String username) {
GrantAccess admin = new GrantAccess();
GrantAccess user = new GrantUserAccess();
if (username.equals("admin")) {
admin.displayAccountStatus();
} else {
user.displayAccountStatus();
}
}
public static void main(String[] args) {
choose("user");
}
}
|
...
Exceptions
MET07-EX0: Occasionally, an API provides hidden methods. Invoking those methods is not a violation of this rule , provided that all invocations of hidden methods use qualified names or method invocation expressions that explicitly indicate which specific method is invoked. If the displayAccountStatus()
were a hidden method, for example, the following implementation of the choose()
method would be an acceptable alternative:
Code Block | ||
---|---|---|
| ||
public static void choose(String username) {
if (username.equals("admin")) {
GrantAccess.displayAccountStatus();
} else {
GrantUserAccess.displayAccountStatus();
}
}
|
...
Rule | Severity | Likelihood | Remediation Cost | Priority | Level |
---|---|---|---|---|---|
MET07-J | low Low | unlikely Unlikely | medium Medium | P2 | L3 |
Automated Detection
Automated detection of violations of this rule is straightforward. Automated determination of cases where in which method hiding is unavoidable is infeasible. However, determining whether all invocations of hiding or hidden methods explicitly indicate which specific method is invoked is straightforward.
Bibliography
Puzzle 48. , "All I get is static Get Is Static" | |
[JLS 2005] | |
...