Method Hiding in Java: Static Methods vs Overriding

Method hiding in Java happens when a subclass redeclares a static method. See how it differs from overriding, the compiler rules and safer designs.

Method hiding resolved from the declared type versus method overriding resolved from the object type

Method hiding in Java happens when a subclass declares a static method with the same signature as a static method in its superclass, so the subclass method hides the parent method instead of overriding it. The compiler picks a hidden method from the type named in the call, never from the runtime class of an object.

We meet method hiding in utility and factory classes that extend each other, and in test helpers that redeclare a static method of the class they extend. It matters because code that looks like an override does not behave like one.

The following example declares a static method source() and an instance method name() in a base configuration class, and redeclares both in a subclass.

class AppConfig {
    static String source() { return "defaults"; }
    String name() { return "app"; }
}

class TestConfig extends AppConfig {
    static String source() { return "test file"; }
    @Override
    String name() { return "test"; }
}
AppConfig config = new TestConfig();
String viaParent = AppConfig.source();     // "defaults"
String viaChild = TestConfig.source();     // "test file"
String overridden = config.name();         // "test"

Notice that each class name calls its own source(), while the instance method name() runs the TestConfig version through an AppConfig variable. We compare hiding with overriding, show where the compile-time choice surprises people, list the rules the compiler checks, cover field hiding and look at the safer designs.

1. Method Hiding vs Method Overriding

An instance method belongs to an object, so the JVM looks at the object at runtime and runs the most specific version. A static method belongs to a class, and no object is involved in the call. So the compiler decides which static method to call from the class name, or from the declared type of the expression in front of the dot, and writes that class into the bytecode.

Method hiding resolved from the declared type versus method overriding resolved from the object type
The declared type picks a hidden static method, while the object picks an overridden instance method

The Java Language Specification uses the word hiding for static methods and overriding for instance methods. Both words describe a subclass method with the same signature, but they lead to different behavior.

AspectMethod hidingMethod overriding
Applies tostatic methodsInstance methods
Chosen byCompiler, from the type in the callJVM, from the runtime class of the object
PolymorphicNoYes
@Override allowedNo, compile errorYes, recommended
Call the parent versionAppConfig.source()super.name() inside the subclass
Return type, access, throwsSame rules as overridingCompatible type, same or wider access, no broader checked exceptions

The full list of override rules is in our article on method overloading and overriding, and hiding follows the same rules for the signature, the return type, access and exceptions.

2. Where the Compile-Time Choice Surprises Us

Java lets us call a static method through a reference variable, which hides the fact that no object takes part in the call. The compiler replaces the variable with its declared type, so the object it points to does not matter.

The following example reuses the two classes from the intro. The variable config holds a TestConfig object, but its declared type is AppConfig.

AppConfig config = new TestConfig();
String fromVariable = config.source();     // "defaults", declared type wins
AppConfig nothing = null;
String fromNull = nothing.source();        // "defaults", no NullPointerException

The second call proves the point, because a call on a null reference would throw NullPointerException if the object were used. With javac -Xlint:static, both lines get the warning static method should be qualified by type name, AppConfig, instead of by an expression, and most IDEs show the same hint.

A second surprise comes from inherited static methods that call other static methods. The call inside the parent class is bound to the parent class, so a subclass cannot change it by hiding the method.

class Report {
    static String header() { return "Report"; }
    static String title() { return header() + " v1"; }
}

class SalesReport extends Report {
    static String header() { return "Sales"; }
}
String parentTitle = Report.title();       // "Report v1"
String childTitle = SalesReport.title();   // "Report v1", not "Sales v1"

The method title() exists only in Report, and its call to header() was compiled as Report.header(). A subclass with instance methods would get “Sales v1”, which is what the author of SalesReport expected.

3. Rules the Compiler Checks for Hidden Methods

A hiding method must keep the contract of the method it hides, as described in JLS 8.4.8.3. The compiler reports a broken rule with the same messages it uses for overriding.

  • The return type must be the same or a subtype, so static Object source() cannot hide static String source().
  • The access level must be the same or wider, otherwise the error says attempting to assign weaker access privileges; was protected.
  • The throws clause cannot add a broader checked exception, otherwise the error says overridden method does not throw Throwable.
  • A static final method cannot be hidden, and the error says overridden method is static,final.
  • Putting @Override on a static method fails with static methods cannot be annotated with @Override.

A static method and an instance method with the same signature cannot replace each other in either direction. Removing the static keyword in the subclass gives one error, and adding it gives the other.

// does not compile: source() in TestConfig cannot override source() in AppConfig, overridden method is static
class TestConfig extends AppConfig {
    String source() { return "test file"; }
}
// does not compile: name() in TestConfig cannot override name() in AppConfig, overriding method is static
class TestConfig extends AppConfig {
    static String name() { return "test"; }
}

Two cases never involve hiding at all. A private static method is not inherited, so a subclass method with the same signature is unrelated and compiles. A static method of an interface is not inherited by implementing classes either, so it can only be called with the interface name, such as List.of().

4. Field Hiding

Fields are never overridden, whether they are static or not. A subclass field with the same name as a parent field hides it, even when the types differ, and the compiler picks the field from the declared type, in the same way as for a static method.

class Plan {
    static String tier = "basic";
    int seats = 1;
}

class TeamPlan extends Plan {
    static String tier = "team";
    int seats = 10;

    int parentSeats() { return super.seats; }
}
Plan plan = new TeamPlan();
int declaredSeats = plan.seats;            // 1, declared type Plan
int realSeats = ((TeamPlan) plan).seats;   // 10
int hiddenSeats = new TeamPlan().parentSeats(); // 1, via super
String tier = TeamPlan.tier;               // "team"

The TeamPlan object holds two seats fields, and the code sees a different one depending on the variable type. We avoid field hiding by keeping fields private and reading them through methods, which can be overridden.

5. Why Method Hiding Leads to Bugs and What to Use Instead

The SEI CERT rule MET07-J says not to declare a class method that hides a method of a superclass, because readers expect polymorphic behavior that never happens.

Say a payment service gets the current time from AppClock.now(), a static method. A developer writes FixedClock extends AppClock with its own static now() that returns a fixed date, and passes a FixedClock object to the service in a test. The service still calls AppClock.now(), so the test uses the real clock and fails on some days only.

When a subclass must change the behavior, the method must be an instance method, and the caller must work with an object instead of a class name. The following version uses an interface, so each implementation overrides now(), and the service gets the clock through its constructor.

interface TimeSource {
    LocalDate now();
}

record FixedTime(LocalDate date) implements TimeSource {
    @Override
    public LocalDate now() { return date; }
}
class InvoiceService {
    private final TimeSource time;

    InvoiceService(TimeSource time) { this.time = time; }

    String dueDate() { return time.now().plusDays(30).toString(); }
}
TimeSource fixed = new FixedTime(LocalDate.of(2026, 1, 1));
String due = new InvoiceService(fixed).dueDate();  // "2026-01-31"

In production, the app passes LocalDate::now as the TimeSource, and the JDK already offers java.time.Clock with Clock.fixed() for the same purpose. When we do keep static methods, we call them with the class name, never through a variable, so the code shows which method runs.

6. Method Hiding FAQs

Each of these questions comes down to the difference between static and instance methods.

6.1. Can we override a static method in Java?

No. A subclass can declare a static method with the same signature, but it hides the parent method. The call is resolved from the type in the call at compile time, so there is no runtime polymorphism for static methods.

6.2. Is method hiding compile-time polymorphism?

Not in the usual sense. Compile-time polymorphism normally means overloading, where one name has several parameter lists. Method hiding is a subclass method that replaces the parent method only for calls that name the subclass type.

6.3. How do we call the hidden parent method?

We call it with the parent class name, such as AppConfig.source(). Inside an instance method of the subclass, super.source() also compiles and runs the parent version, but javac -Xlint:static warns about it, so the class name is the clearer choice.

6.4. Does method hiding apply to private or final methods?

No for private methods, because they are not inherited, so a subclass method with the same signature is a separate method. A static final method cannot be hidden, and the compiler rejects the attempt with overridden method is static,final.

6.5. Does method hiding work with interfaces?

No. Static methods of an interface are not inherited by implementing classes or sub-interfaces, so there is nothing to hide. An implementing class can declare a static method with the same name, and the two methods are unrelated.

7. Conclusion

Method hiding is what happens to a static method that a subclass redeclares. The compiler binds every call to the class named in the call, or to the declared type of the variable, so the object never decides which method runs.

The compiler checks the same signature rules as for overriding, rejects @Override on static methods and refuses to mix static and instance methods with the same signature. Fields behave the same way and are hidden, not overridden. When we need behavior that changes per subclass, we use instance methods with @Override, and we call any remaining static methods by class name. The other building blocks are covered in our object-oriented programming guide.

8. References

Happy Learning !!

Source Code on Github

Leave a Comment

  1. Hi Team,

    Nice article,

    But i want to give some input on overloading and static overloading.

    overloading :- Think a new function
    overriding :- subclass override method of parent class

    More information (looks concept of method area)

    References :- create in compile time
    Object :- Create in runtime

    Static :- Class level
    instance method :- depends on object

    Might be @Bharat Shivram will be got his answer

    i.e static method depends only and only references not instance (object)

    so that you will get a,d

Comments are closed.

About Us

HowToDoInJava provides tutorials and how-to guides on Java and related technologies.

It also shares the best practices, algorithms & solutions and frequently asked interview questions.