Method That Cannot Be An Override
ID |
java.child_method_not_an_override |
Severity |
high |
Remediation Complexity |
trivial |
Remediation Risk |
low |
Remediation Effort |
low |
Resource |
Code Smell |
Language |
Java |
Tags |
code-smell, inheritance |
Description
Reports a subclass method that shares its name and parameter types with a method of its direct
parent, where exactly one of the two is static. Java resolves a static method by the
reference’s declared type and never by dynamic dispatch, so a static method and an instance
method can never override one another however alike their signatures look. The author believes the
subclass now controls what runs; the parent’s original method keeps running for every caller that
holds a reference typed as the parent.
The pair only reaches this rule when the parent’s method is not inherited by the subclass —
otherwise javac rejects the mismatch outright (JLS 8.4.8.1 and 8.4.8.2: an instance method
cannot override a static one, and a static method cannot hide an instance one). The shape that
compiles, and the one this rule is about, is a parent method the subclass cannot inherit because
it is not accessible from there — package-private, with the subclass in a different package.
Rationale
// ---- com/acme/io/Connection.java -------------------------------------------------------------
package com.acme.io;
public class Connection {
static void open() { // package-private: a static factory-style helper
// ...
}
}
// ---- com/acme/pool/PooledConnection.java -----------------------------------------------------
package com.acme.pool;
import com.acme.io.Connection;
public class PooledConnection extends Connection {
public void open() { // FLAW — looks like it replaces the parent's open()
// ...
}
}
Connection.open() and PooledConnection.open() are two unrelated methods that happen to share a
name. The subclass is in a different package, so the parent’s package-private open() is not
inherited and the declaration compiles. Any code inside com.acme.io that calls open() runs the
parent’s version, never the subclass’s, regardless of which concrete type the reference points
to.
Remediation
If an override was genuinely intended, fix the mismatch: match the parent’s static modifier, and
widen the parent’s method so the subclass can actually inherit it. If the two methods are meant to
be unrelated, rename the subclass’s method so nothing suggests a relationship that does not exist.
public class PooledConnection extends Connection {
public static void open() { // matches the parent's modifier: hides it, as intended
// ...
}
}
Limitations
The parent class is declared in another file, so this rule resolves it through the project-wide
software model. When the model has no entry for the parent, or the parent’s method table has no
method with the same name and the same parameter types, the rule stays silent. Only the
direct parent is examined — a method inherited from a grandparent is out of scope. A method
annotated @Override is never reported: it is an intended override, and the compiler already
rejects a broken one. A private parent method is never reported either: it is invisible from the
subclass, so no call can dispatch to the wrong one of the two and there is nothing to fix.
Upstream also flags a same-name, same-arity method whose parameter types resolve to a different package than the parent’s (the classic "wrong import" mistake); this rule does not attempt that comparison and treats it as a documented false negative rather than a guess.