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.

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.
| Aspect | Method hiding | Method overriding |
|---|---|---|
| Applies to | static methods | Instance methods |
| Chosen by | Compiler, from the type in the call | JVM, from the runtime class of the object |
| Polymorphic | No | Yes |
| @Override allowed | No, compile error | Yes, recommended |
| Call the parent version | AppConfig.source() | super.name() inside the subclass |
| Return type, access, throws | Same rules as overriding | Compatible 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
- JLS 25, Hiding (by Class Methods)
- JLS 25, Field Declarations and Hiding
- Oracle Java Tutorials, Overriding and Hiding Methods
- SEI CERT MET07-J, Never declare a class method that hides a method declared in a superclass or superinterface
Happy Learning !!
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