🧬 Inheritance & Polymorphism · Intermediate

Field hiding & static method hiding in Java

Fields and static methods are not polymorphic.

🧩 The mysteryOne object. p.tag says "P". p.getTag() says "C". Same object, same name, two different answers. Welcome to hiding.

Only instance methods are polymorphic

Dynamic dispatch applies only to instance methods. Fields and static methods are picked by the declared type at compile time — the runtime object is never consulted.

🔮 Predict it

Field vs method

What does this print?

class Parent {
    String tag = "P";
    String getTag() { return tag; }
}
class Child extends Parent {
    String tag = "C";
    String getTag() { return tag; }
}
Parent p = new Child();
System.out.println(p.tag + p.getTag());
  1. CC
  2. PC
  3. PP
  4. CP
Show the answer

PC. p.tag is a field access, resolved by the declared type Parent → "P". p.getTag() is an instance method, dispatched to Child → "C".

Two fields in one object

A field with the same name in a subclass doesn't replace the parent's — it hides it. A Child object contains both tag fields. Which one you see depends on the reference type; cast to see the other.

Parent p = new Child();
String t1 = p.tag;            // "P"
String t2 = ((Child) p).tag;  // "C"

Static methods hide too

A static method with the same signature in a subclass hides the parent's. a.id() with A a = new B(); is compiled as A.id() — the object is irrelevant.

class A { static String id() { return "A"; } }
class B extends A {
    static String id() { return "B"; }
}
A a = new B();
a.id();  // "A"
🤔 Think first

Why no @Override on statics?

Why can't you put @Override on a static method that matches a parent's static method?

Think about it, then reveal the answer

Because there's nothing to override. Overriding means dynamic dispatch on an instance; static methods belong to classes. A same-signature static method only hides the parent's, so @Override is rejected.

⚠️ The trap

Static vs instance clash

An instance method can't override a static one, and a static method can't hide an instance one. Mixing them with the same signature is a compile error.

class A { static void go() { } }
class B extends A {
    void go() { }  // compile error
}
💼 In the real world

In real projects

Hidden fields are almost always accidents, which is why IDEs warn about them. Same for calling statics through instances (a.id()): linters flag it and recommend A.id(), so nobody believes it's polymorphic.

Key takeaways

  1. Fields are chosen by the declared type
  2. Static methods are chosen by the declared type
  3. Hiding is not overriding: no dynamic dispatch
  4. An instance method can't override a static one
🤯 Did you know?

A hiding field doesn't even need the same type: a subclass can declare int name that hides the parent's String name.

Practice questions

What does this print?

class A { String name = "A"; }
class B extends A { String name = "B"; }
void main() {
    A a = new B();
    System.out.println(a.name + ((B) a).name);
}
  1. BB
  2. AB
  3. AA
  4. BA
Check your answer

AB. A B object contains both fields. Through an A reference you see A's name; after casting to B you see B's.

What does this print?

class A { static String id() { return "A"; } }
class B extends A {
    static String id() { return "B"; }
}
void main() {
    A a = new B();
    System.out.println(a.id());
}
  1. A
  2. B
  3. Compile error
Check your answer

A. Static methods are not dispatched on the object. a.id() is compiled as A.id() because a is declared as A.

Next: how to say "no subclasses allowed" — final classes and methods.