skip to content

Why can't static methods be overridden in Java, and what happens if a subclass declares a static method with the same signature?

level: middleimportance: should knowfreq 55%

answer

  1. Static = belongs to class, no receiver object
  2. No object ⇒ no runtime type ⇒ no dynamic dispatch
  3. Same-signature static in subclass = hiding
  4. Call binds to the declared/compile-time type
  5. @Override on a static = compile error

basics

~20 s

Static methods belong to the class, not to an object, so there's no object whose runtime type could pick a version — Java just uses the declared type at compile time. A same-signature static method in a subclass hides the parent's, it doesn't override it.

solid answer

~50 s

Overriding relies on dynamic dispatch, which needs an *instance* whose runtime type selects the method body. Static methods belong to the class itself, not to any instance, so there's no runtime object to dispatch on — resolution is done at compile time by the declared type. When a subclass declares a static method with the same signature, it *hides* the parent's: `Parent.foo()` and `Child.foo()` are two separate methods, and a call binds to whichever the compile-time type names. Calling a static method through a reference (which is legal but discouraged) uses that reference's declared type, so `Parent p = new Child(); p.foo();` runs `Parent.foo()`. You cannot put `@Override` on it — the compiler rejects that, which is the signal that it isn't an override. The takeaway: don't redeclare statics across a hierarchy; if you need polymorphic behavior, use instance methods.

go deeper

for a junior

Knows static methods belong to the class and are called by class name; may not know what happens when a subclass redeclares one.

for a middle

Explains that statics are hidden not overridden, that resolution is by declared type, and that @Override won't compile on them.

for a senior

Articulates the no-receiver/no-vtable reasoning, predicts the p.foo() outcome, and knows the static↔instance switch is a compile error.

for a principal

Frames static hiding as an anti-pattern, steers designs toward instance-method polymorphism or strategy objects, and enforces 'call statics by class name' in code standards.

## Why overriding needs an instance **Overriding** is the mechanism behind polymorphism: a subclass supplies a new body for an inherited **instance method**, and at call time the JVM performs **dynamic dispatch** — it inspects the **runtime type** of the receiving object and runs that type's version. The critical word is *receiving object*. Dynamic dispatch is a lookup keyed on the object's actual class (conceptually, the object carries a pointer to its class's method table — the *vtable* — and the JVM indexes into it). **Without an object, there is nothing to dispatch on.** ### Static methods have no receiver A **static method** is declared with the `static` keyword and belongs to the **class itself**, not to any instance. You can call `Math.max(...)` without ever creating a `Math`. Because there is no instance, there is no runtime type to consult — so the JVM resolves the call at **compile time** using the **declared (compile-time) type**. This is **static binding**. ### Hiding, not overriding If `Child extends Parent` and both declare `static void foo()`, the child's `foo` **hides** the parent's. They are two distinct methods that happen to share a name: ```java class Parent { static void foo() { System.out.println("P"); } } class Child extends Parent { static void foo() { System.out.println("C"); } } Parent.foo(); // P Child.foo(); // C Parent p = new Child(); p.foo(); // P — declared type is Parent (static binding) ``` The last line is the gotcha. Even though the object is a `Child`, the static method is selected by `p`'s **declared type** `Parent`. (Calling a static method *through an instance reference* is legal but discouraged precisely because it reads like a polymorphic call when it isn't — most IDEs warn and suggest `Parent.foo()`.) ### @Override won't compile You cannot annotate the hiding static method with `@Override`: ```java class Child extends Parent { @Override static void foo() {} // COMPILE ERROR } ``` The compiler error is the explicit signal: a static method does not override anything. This is one reason to always write `@Override` on intended overrides — it catches the mistake of accidentally marking a method `static` or otherwise breaking the override. ### Rules and edge cases - A subclass **cannot** change a method from static to instance (or vice versa) while keeping the same signature — that's a compile error, not a hide. - The hiding method's access level can differ; there is no 'access may only widen' override rule because it isn't an override. - Hidden static methods are still reachable: `Parent.foo()` always works, and from inside `Child` you can call the parent's via the class name `Parent.foo()`. ### The design takeaway Because hiding looks like overriding but behaves by declared type, it is a readability and correctness hazard. **Don't redeclare static methods down a hierarchy.** If you need behavior that varies by subtype, model it with **instance methods** (which override) — possibly behind a factory or a strategy object. Always call static methods on the class name, never through an instance. ### Summary rule > **No instance ⇒ no runtime type ⇒ no dynamic dispatch ⇒ no overriding.** Static methods are *hidden* and bound by the declared type at compile time.

  • Is it legal to call a static method through an instance reference, and should you?
    It's legal — `p.foo()` compiles — but discouraged. It resolves by p's declared type, not the object, which misleads readers into expecting polymorphism. Call statics on the class name (Parent.foo()); most linters/IDEs flag the instance form.
  • Can a subclass turn an inherited static method into an instance method with the same signature?
    No. Changing static↔instance while keeping the same signature is a compile error, not a hide or override. Static and instance methods with the same signature cannot coexist across the hierarchy.

saying these in an interview costs you the question

  • Saying static methods 'override' the parent's
  • Expecting p.foo() to pick the runtime type for a static method
  • Thinking @Override works (or is optional but valid) on statics
  • Calling static methods through instance references as if polymorphic

context