skip to content

Predict the output: with `Parent p = new Child();`, where Child overrides a method and shadows a same-named field, what does calling the method vs reading the field return, and why?

level: middleimportance: should knowfreq 45%

answer

  1. Methods follow the object; fields follow the reference
  2. Overridden method → Child; shadowed field → Parent
  3. Casting the reference changes which shadowed field you read
  4. Same object, different static type → different field value
  5. Use a getter, not a field, for subclass-specific values

basics

~20 s

The method call returns Child's version because instance methods are dynamically bound to the object's real type (Child). The field read returns Parent's value because fields are statically bound to the reference's declared type (Parent). Methods follow the object; fields follow the reference.

solid answer

~50 s

When you write `Parent p = new Child();`, the variable `p` has declared (compile-time) type Parent but points to a Child object. Calling an overridden instance method, `p.describe()`, uses dynamic binding: the JVM dispatches on the actual object's class, so Child's override runs. Reading a shadowed field, `p.name`, uses static binding: the field is resolved at compile time against the declared type Parent, so you get Parent's field — even though the object is a Child. The reason is that Java fields are never polymorphic; only methods are. A same-named field in a subclass *shadows* the parent's, and which one you see depends entirely on the reference's declared type, not the runtime type. The fix, if you want the subclass value, is to access it through a method (a getter the subclass overrides) rather than a field.

code

java · 13 lines
java
class Parent {
    String name = "parent-field";
    String describe() { return "parent-method"; }
}
class Child extends Parent {
    String name = "child-field";                 // shadows, not overrides
    @Override String describe() { return "child-method"; }
}

Parent p = new Child();
System.out.println(p.describe());      // child-method  (dynamic: runtime type Child)
System.out.println(p.name);            // parent-field  (static: declared type Parent)
System.out.println(((Child) p).name);  // child-field   (cast changes static type)

go deeper

for a junior

Can state methods give the Child result and fields the Parent result, even if shaky on the precise reason.

for a middle

Explains it via dynamic binding for methods and static binding (declared type) for fields, and recognizes shadowing vs overriding.

for a senior

Demonstrates with casts that field binding is purely compile-time and advises exposing specialization via methods, not fields.

for a principal

Connects to API design — warns against protected mutable shadowed fields, prefers methods for extensibility, and reasons about the maintenance hazards of field hiding across a hierarchy.

## The setup ```java class Parent { String name = "parent-field"; String describe() { return "parent-method"; } } class Child extends Parent { String name = "child-field"; // shadows Parent.name @Override String describe() { return "child-method"; } // overrides } Parent p = new Child(); System.out.println(p.describe()); // ? System.out.println(p.name); // ? ``` ## Reasoning step by step `p` has two types: - **Compile-time (declared) type:** `Parent` — what the compiler knows. - **Runtime (actual) type:** `Child` — the real object on the heap. **`p.describe()` → "child-method".** Instance methods use **dynamic (late) binding**. The compiler records only the signature `describe()`; at run time the JVM looks at the object's actual class (`Child`) and runs the most-derived override. This is runtime polymorphism in action. **`p.name` → "parent-field".** Field access uses **static (early) binding**. The compiler resolves `name` immediately against the **declared type** of `p`, which is `Parent`, and emits a fixed reference to `Parent.name`. The object being a `Child` is irrelevant — fields are never polymorphic. A subclass field of the same name doesn't *override*, it *shadows*; both fields physically exist in the object, and which you see depends only on the reference type you go through. ## Proving fields follow the reference type ```java Child c = new Child(); Parent pc = c; c.name; // "child-field" (declared type Child) pc.name; // "parent-field" (declared type Parent) - same object! ((Parent) c).name; // "parent-field" (cast changes the static type) ((Child) p).name; // "child-field" (cast to Child) ``` The *same* Child object yields different field values depending on the static type of the expression — definitive proof that field binding is compile-time, not runtime. ## Why this is a trap (and how to avoid it) Programmers expect everything to be polymorphic, but only methods are. Common consequences: - A `protected` field redeclared in a subclass silently shadows the parent's, leading to two independent fields and confusing reads/writes through different static types. - Code that reads a base-typed reference's field gets the base value even when a subclass "meant to change it." **Best practice:** don't shadow fields. If a subclass must specialize a value, expose it through an overridable **method** (a getter), because methods are dynamically bound: ```java class Parent { String name() { return "parent"; } } class Child extends Parent { @Override String name() { return "child"; } } Parent p = new Child(); p.name(); // "child" -> dynamic dispatch does what you wanted ``` ## One-line summary **Methods follow the object (runtime type); fields follow the reference (compile-time type).**

  • Does casting `p` to `Child` change which describe() override runs?
    No. The method already dispatches on the runtime type, so it always runs Child's override regardless of the cast. Casting only changes the compile-time type, which affects field access and overload selection, not method override dispatch.
  • How do you make the subclass value win for what looks like a field?
    Expose it through an overridable method (a getter). Methods are dynamically bound, so the subclass override returns the subclass value even through a parent-typed reference.

saying these in an interview costs you the question

  • Predicting the field read returns Child's value
  • Saying the subclass field 'overrides' the parent field (it shadows)
  • Thinking a cast changes which method runs (it doesn't — only the static type, hence fields)
  • Believing both reads go through the runtime type

context