Back to Blog
Java

Java Method Hiding Explained with Code Examples

Understand how java method hiding works for static methods, how it differs from overriding, and where it causes subtle bugs.

Javastatic methodsmethod overridinginheritanceOOP
Diagram of a parent class and subclass each declaring a static method with the same signature, showing compile-time binding to the declared reference type.

Java method hiding is what happens when a subclass declares a static method with the same signature as a static method in its parent class. The subclass method does not override the parent method; it hides it. The difference matters because the two mechanisms resolve calls differently: overriding uses dynamic dispatch based on the runtime object type, while method hiding binds the call at compile time based on the declared reference type.

What Method Hiding Looks Like

Consider two classes where the child redeclares a static method that already exists in the parent:

public class Parent { static void announce() { System.out.println("Parent.announce"); } } public class Child extends Parent { static void announce() { System.out.println("Child.announce"); } }

Both methods are valid, and which one runs depends entirely on how you call it:

Parent p = new Child(); p.announce(); // prints "Parent.announce" Child c = new Child(); c.announce(); // prints "Child.announce"

Even though p holds a Child instance, the call p.announce() invokes Parent.announce. The compiler sees the declared type Parent and binds the static call to that class. This is the defining characteristic of method hiding and the source of most confusion around it.

Method Hiding vs Method Overriding

The same code shape with instance methods behaves completely differently:

public class Animal { void speak() { System.out.println("Animal speaks"); } } public class Dog extends Animal { @Override void speak() { System.out.println("Dog barks"); } }
Animal a = new Dog(); a.speak(); // prints "Dog barks"

Here the runtime object is a Dog, so the overridden method runs. The reference type does not decide the outcome. With static methods it does, because static calls are resolved at compile time.

BehaviorStatic method (hiding)Instance method (overriding)
Resolution timeCompile timeRuntime
Depends onDeclared reference typeRuntime object type
@Override allowedNoYes
Covariant return typeAllowedAllowed

The @Override annotation is a compile error on a static method, because a static method never overrides anything; it can only hide.

Rules and Constraints

A few hard rules govern method hiding in Java.

A static method can only hide another static method. Declaring a static method with the same signature as an inherited instance method is a compile error, and so is declaring an instance method that matches an inherited static method.

The hiding method must provide at least as much access as the hidden method. You cannot hide a public static method with a private one, for example. This mirrors the access rule for overriding.

Covariant return types are permitted. A subclass static method may return a subtype of the parent method's return type, and the call still resolves according to the reference type.

Calling the Hidden Method

When a subclass hides a parent static method, the parent version is still reachable. The clearest way is to call it through the parent class name:

public class Child extends Parent { static void announce() { System.out.println("Child.announce"); } static void callParentVersion() { Parent.announce(); } }

Inside the subclass you can also use super.announce(), and it resolves to the same hidden method. Most codebases prefer the explicit Parent.announce() form because it leaves no doubt about which class is being called.

Fields Are Hidden Too

Field hiding follows the same compile-time rule. A subclass field with the same name as a parent field hides it, and access depends on the reference type:

public class Base { String label = "base"; } public class Derived extends Base { String label = "derived"; }
Base b = new Derived(); System.out.println(b.label); // prints "base"

Developers frequently confuse field hiding with method hiding because the symptoms look similar. The underlying mechanism is the same: compile-time resolution against the declared type.

Common Pitfalls

The most frequent mistake is calling a static method through an instance reference and expecting dynamic dispatch:

Parent p = new Child(); p.announce(); // looks like it should print "Child.announce"

IDEs typically warn when a static method is invoked through an instance, and for good reason — the call site reads as if it were polymorphic.

Another common error is reaching for @Override on a static method. The compiler rejects it. If you want the annotation to work, the method must be an instance method.

Mixing static and instance methods with the same signature is also a compile error. You cannot convert an inherited static method into an instance method in a subclass, or the reverse.

Maintainability: Why Hiding Confuses Callers

Method hiding is a maintainability hazard because the behavior of a call site depends on the declared type, which is often not obvious when reading the code. Two callers holding the same object can get different results depending on the static type of their variable:

Parent p = new Child(); Child c = (Child) p; p.announce(); // "Parent.announce" c.announce(); // "Child.announce"

The same object produces two different outputs. This violates the intuition most developers carry from polymorphism, where the runtime type governs behavior. It also makes refactoring risky: changing a variable's declared type can silently change which static method runs, with no compiler warning.

For these reasons, hiding a static method is rarely the right design. If a subclass needs different behavior, prefer a distinct method name, or make the method an instance method so overriding applies. Keeping static methods non-polymorphic and clearly named reduces the chance of subtle bugs.

When Hiding Is Acceptable

There are a few legitimate uses. A subclass may deliberately hide a static factory method to return a more specific type, taking advantage of the covariant return rule:

public class OrderParser { static Order parse(String input) { return new Order(input); } } public class DiscountOrderParser extends OrderParser { static DiscountOrder parse(String input) { return new DiscountOrder(input); } }

Callers using DiscountOrderParser.parse get the subtype, while callers using OrderParser.parse get the base type. This works, but it still carries the same readability cost, so it should be a deliberate decision with a comment explaining why the name is reused.

java method hiding: Practical Usage and Code Examples | RYUSLOG DEV