Back to Polymorphism
Q6Question 6 of 7

What is method hiding vs method overriding?

Key Concepts
  • Overriding (instance methods): resolved at runtime based on the actual object type via vtable (dynamic dispatch)
  • Hiding (static methods): resolved at compile time based on the reference variable type (static binding)
  • Parent p = new Child(); p.staticMethod() calls Parent's version (hiding, no polymorphism)
  • Parent p = new Child(); p.instanceMethod() calls Child's version (overriding, polymorphism)
  • Same object, different reference type produces different static results: proof of compile-time binding
  • Never call static methods on instance references: it misleads developers about the binding mechanism

Definition

Overriding (instance): runtime dispatch based on actual object type. Hiding (static): compile-time binding based on reference type. Overriding is polymorphism. Hiding is not polymorphism.

Two different mechanisms exist for methods with the same name in parent and child.

  • Method overriding (instance methods): the child redefines a parent's instance method. Resolution at runtime: the JVM checks the actual object type in the heap and dispatches via the vtable. Account ref = new SavingsAccount() followed by ref.getDescription() calls SavingsAccount's version.
  • Method hiding (static methods): the child defines a static method with the same signature as the parent's static method. Resolution at compile time: the compiler checks the variable type (reference type) and binds to that class's static method. Account ref = new SavingsAccount() followed by ref.getPolicy() calls Account's version.
  • Hiding is not polymorphism: no dynamic dispatch occurs. The child's static method simply shadows the parent's in the child's namespace.
  • Proof: same object, different reference type produces different static results.

Overriding: Rajesh calls the customer service number at National Bank of India. The system checks his actual account type at runtime and routes to the SavingsAccount team. Same number, different handler based on who is calling. Hiding: the bank's website shows the standard policy page. If you navigate to the Savings Division's website, you see their policy page. But if you use the main bank URL (parent reference), you always see the main page. The website does not check your account type.

Understanding the Concepts

What is method hiding vs method overriding?

The critical difference is when and how the method call is resolved.

How do instance methods and static methods behave differently?

JAVA
package com.bank.core;

public class Account {
    // Instance method: will be overridden
    public String getDescription() { return "Generic Account"; }

    // Static method: will be hidden
    public static String getPolicy() { return "Standard Banking Policy"; }
}

public class SavingsAccount extends Account {
    // Overrides parent's instance method
    @Override
    public String getDescription() { return "Savings Account (4% interest)"; }

    // Hides parent's static method (not @Override: hiding)
    public static String getPolicy() { return "Savings Special Policy"; }
}

What happens through a parent reference?

JAVA
Account ref = new SavingsAccount("SAV001", java.math.BigDecimal.ZERO);

// Instance method: resolved at runtime (actual object = SavingsAccount)
String desc = ref.getDescription();
// Result: "Savings Account (4% interest)" -- JVM dispatches to SavingsAccount

// Static method: resolved at compile time (reference type = Account)
String policy = ref.getPolicy();
// Result: "Standard Banking Policy" -- Account's version, NOT SavingsAccount's
// Compiler sees ref is Account -> binds to Account.getPolicy().

How can you prove it is hiding and not overriding?

Change the reference type without changing the object. The static result changes but the instance result does not.

JAVA
SavingsAccount saRef = new SavingsAccount("SAV001", java.math.BigDecimal.ZERO);

// Same object, child reference
String saPolicy = saRef.getPolicy();       // "Savings Special Policy"
String saDesc = saRef.getDescription();     // "Savings Account (4% interest)"

// Same object, parent reference
Account accRef = saRef;
String accPolicy = accRef.getPolicy();     // "Standard Banking Policy" (changed!)
String accDesc = accRef.getDescription();   // "Savings Account (4% interest)" (same)

// The object did not change. Only the reference type changed.
// Static result changed -> compile-time binding to reference type.
// Instance result stayed -> runtime binding to actual object type.

Why can static methods not be overridden?

Static methods belong to the class, not to an instance. They are resolved at compile time using the class name. There is no vtable entry for static methods, so no dynamic dispatch mechanism exists.

What is the practical impact?

If a developer calls a static method on an instance variable expecting polymorphism, the result is wrong.

JAVA
public class AccountService {
    public void process(Account account) {
        // Instance: works polymorphically
        String desc = account.getDescription(); // correct: SavingsAccount version

        // Static: does NOT work polymorphically
        String policy = account.getPolicy(); // always Account's version!
        // Developer thinks: "I have a SavingsAccount, so getPolicy() returns savings policy."
        // Reality: ref type is Account -> Account.getPolicy() called.
    }
}

// FIX: never call static methods on instance variables.
// Use: Account.getPolicy() or SavingsAccount.getPolicy() explicitly.

How do overriding and hiding compare?

| Aspect | Overriding (instance) | Hiding (static) |
|--------|----------------------|------------------|
| Method type | Instance | Static |
| Resolution time | Runtime | Compile time |
| Based on | Actual object type | Reference variable type |
| Polymorphism | Yes (dynamic dispatch) | No (static binding) |
| @Override | Required | Not applicable |
| Vtable entry | Yes | No |

What are common mistakes?

The most common mistake is calling static methods on instance references and expecting polymorphism.

JAVA
// WRONG: expecting dynamic dispatch for static method
Account ref = new SavingsAccount();
ref.getPolicy(); // returns Account's policy, not SavingsAccount's

// CORRECT: call static methods on class name
Account.getPolicy();         // "Standard Banking Policy"
SavingsAccount.getPolicy();  // "Savings Special Policy"

What should a senior engineer know?

  • IntelliJ IDEA warns when static methods are called on instance references because it misleads about the binding mechanism.
  • SonarQube rule S2209 flags this pattern as a code smell.
  • In bytecode, instance methods use invokevirtual (dynamic dispatch), static methods use invokestatic (no dispatch).

Visual Overview

DIAGRAM
  Account ref = new SavingsAccount();

  INSTANCE METHOD (overriding)
  ┌─────────────────────────────────────┐
  │  ref.getDescription()                │
  │         │                            │
  │  Compile: Account has method? Yes.   │
  │  Runtime: actual type? SavingsAccount│
  │         │                            │
  │         ▼                            │
  │  SavingsAccount.getDescription()     │
  │  "Savings Account (4% interest)"     │
  └─────────────────────────────────────┘

  STATIC METHOD (hiding)
  ┌─────────────────────────────────────┐
  │  ref.getPolicy()                     │
  │         │                            │
  │  Compile: ref type? Account.         │
  │  Binds to Account.getPolicy()        │
  │  No runtime check.                   │
  │         │                            │
  │         ▼                            │
  │  Account.getPolicy()                 │
  │  "Standard Banking Policy"           │
  └─────────────────────────────────────┘

Key Takeaway

Method overriding applies to instance methods and uses runtime dispatch: the JVM checks the actual object type in the heap and calls the correct version. Account ref = new SavingsAccount() followed by ref.getDescription() calls SavingsAccount's version because the JVM dispatches based on the actual type. Method hiding applies to static methods and uses compile-time binding: the compiler looks at the reference variable type and binds directly. ref.getPolicy() calls Account's version because the compiler sees ref is declared as Account and never checks the actual object.

The proof: same object, different reference type produces different static results. Account ref = sa followed by ref.getPolicy() returns Standard Banking Policy. SavingsAccount saRef = sa followed by saRef.getPolicy() returns Savings Special Policy. The object did not change. Only the reference type changed. This proves static methods bind at compile time to the reference type. Instance methods bind at runtime to the actual object type.

Remember one sentence: instance methods are overridden (runtime dispatch to actual type), static methods are hidden (compile-time binding to reference type), and calling static methods on instance references is a code smell.

---

Share
Use ← → arrow keys to navigate