skip to content

How does variable shadowing differ from field hiding and from method overriding?

level: seniorimportance: should knowfreq 45%

answer

  1. Shadowing: local vs field, lexical
  2. Hiding: subclass field vs superclass field, by static type
  3. Overriding: methods, by runtime type
  4. Fields never polymorphic
  5. this.x / super.x / cast to reach the other

basics

~20 s

Shadowing is a local or parameter hiding a same-named field in one scope. Field hiding is a subclass field hiding a superclass field of the same name. Overriding is about methods and is chosen at runtime. Only overriding is polymorphic.

solid answer

~50 s

All three involve same-named members, but they are distinct. Shadowing is when a local variable or parameter has the same name as a field; within that scope the local wins, and this.field reaches the field. Field hiding is when a subclass declares a field with the same name as one in a superclass; both fields coexist and which one you access is decided by the compile-time (static) type of the reference, reachable via super.field or a cast. Method overriding is when a subclass provides its own implementation of an inherited method; the call is dispatched at runtime based on the object's actual type, which is true polymorphism. Crucially, fields are never polymorphic: shadowing and hiding are resolved statically, while overriding is resolved dynamically. Relying on field hiding across types is a known pitfall because access depends on the declared type, not the object.

code

java · 6 lines
java
class Base { int v = 1; String who() { return "Base"; } }
class Sub extends Base { int v = 2; @Override String who() { return "Sub"; } }

Base b = new Sub();
System.out.println(b.v);     // 1  -> field hiding, static type Base
System.out.println(b.who()); // Sub -> overriding, runtime type Sub

go deeper

for a junior

Can say shadowing is about a local vs a field; may not yet distinguish hiding from overriding.

for a middle

Separates the three concepts and knows fields are accessed by static type while overridden methods dispatch at runtime.

for a senior

Explains and demonstrates with code why b.v and b.who() differ, knows super./cast access, and flags field hiding as a smell.

for a principal

Articulates the static-vs-dynamic dispatch model precisely, advises team conventions to avoid hiding, and reasons about API/maintainability impact.

## Three look-alikes These terms are frequently confused because each involves two members sharing a name. They behave very differently. ### 1. Shadowing (local/parameter vs field) A **local variable** or **parameter** has the same name as a **field**. Within the local's scope the bare name means the local; `this.field` reaches the field. This is resolved **at compile time** by lexical scope (innermost wins). ```java class A { int x = 1; void m() { int x = 2; System.out.println(x + "," + this.x); } // 2,1 } ``` ### 2. Field hiding (subclass field vs superclass field) A **subclass** declares a field with the same name as a field in its **superclass**. Both fields physically exist in the object. Which one you read depends on the **static (compile-time) type** of the reference, not the runtime object: ```java class Base { int v = 1; } class Sub extends Base { int v = 2; } Base b = new Sub(); System.out.println(b.v); // 1 -> static type Base System.out.println(((Sub) b).v); // 2 -> static type Sub ``` The subclass field **hides** (not overrides) the superclass field. Inside `Sub`, `super.v` reaches the hidden `Base.v`. ### 3. Method overriding (true polymorphism) A subclass provides a new body for an inherited **method** with the same signature. The call is dispatched at **runtime** based on the object's **actual type**: ```java class Base { String who() { return "Base"; } } class Sub extends Base { @Override String who() { return "Sub"; } } Base b = new Sub(); System.out.println(b.who()); // "Sub" -> runtime type wins ``` ## The decisive contrast | Concept | Members | Resolved by | Polymorphic? | |---|---|---|---| | Shadowing | local/param vs field | compile-time (lexical scope) | no | | Field hiding | subclass field vs superclass field | compile-time (static type) | no | | Overriding | method vs method | runtime (object's actual type) | yes | **Fields are never polymorphic.** Both shadowing and hiding are static; only methods override and dispatch dynamically. That is why `b.v` above prints the *Base* field even though the object is a `Sub`, while `b.who()` prints *Sub*. ## Practical guidance - Shadowing a field with a parameter is fine and idiomatic with `this.field = field`. - Field hiding across an inheritance hierarchy is almost always a design smell: it surprises readers who expect polymorphism. Prefer renaming, or expose state via overridable accessor methods. - Use `@Override` so the compiler verifies you are truly overriding a method and not accidentally writing a new one.

  • Why does b.v print the Base value while b.who() prints Sub for the same object?
    Field access (hiding) is resolved by the reference's static type Base, but method calls (overriding) dispatch on the runtime type Sub. Fields are not polymorphic; methods are.
  • How do you reach a hidden superclass field from inside the subclass?
    Use super.fieldName, or cast the reference to the superclass type. From outside, the declared type of the reference selects which field you see.
  • Is field hiding recommended?
    Generally no; it is a design smell because it breaks the polymorphism readers expect. Prefer renaming or accessor methods.

saying these in an interview costs you the question

  • Claiming subclass fields override and dispatch polymorphically
  • Saying b.v depends on the runtime object type
  • Treating shadowing and hiding as the same mechanism
  • Thinking @Override applies to fields

context