Definition
Static inheritance rules:
- Static methods are hidden. A subclass can define a static method with the same signature as the parent's. But the call is resolved by the reference type, not the object type. This is hiding, not overriding.
- No polymorphism.
Parent p = new Child(); p.staticMethod()calls Parent's version because the reference type is Parent. - @Override is rejected. The compiler does not allow
@Overrideon a static method because it cannot be overridden.
Each bank branch (subclass) can post its own rate card (static method) on its wall. But when the head office (parent reference) looks up a rate, it reads its own wall, not the branch's. The branch's card is independent, not a replacement.
Understanding the Concepts
What is method hiding vs overriding?
When a subclass defines a static method with the same signature as the parent's static method, the subclass version hides the parent's. The call is resolved by the reference type at compile time, not the object type at runtime. This is fundamentally different from instance methods, which are overridden and resolved by the actual object type at runtime.
package com.bank.core;
public class Bank {
public static String getType() { return "GENERIC"; } // static
public String getName() { return "National Bank"; } // instance
}
public class SavingsBank extends Bank {
public static String getType() { return "SAVINGS"; } // HIDES parent static
@Override
public String getName() { return "Savings Division"; } // OVERRIDES parent instance
}
Bank b = new SavingsBank();
System.out.println(b.getType()); // "GENERIC" – static: resolved by reference type (Bank)
System.out.println(b.getName()); // "Savings Division" – instance: resolved by object type (SavingsBank)
This is one of the most frequently tested concepts in Java interviews.
Comparison table
| Feature | Instance method | Static method |
|---|---|---|
| Resolved by | Object type (runtime) | Reference type (compile time) |
| @Override | Yes | No (compiler rejects) |
| Polymorphic? | Yes | No |
| Called via | object.method() | ClassName.method() |
| Binding | Late (dynamic dispatch) | Early (compile-time dispatch) |
Can a subclass define the same static field?
Yes, but it creates a separate field (hiding), not an override. Each class has its own independent copy of the field.
public class Bank {
static String country = "INDIA";
}
public class InternationalBank extends Bank {
static String country = "GLOBAL"; // hides, does not replace
}
System.out.println(Bank.country); // INDIA
System.out.println(InternationalBank.country); // GLOBAL
Bank b = new InternationalBank();
System.out.println(b.country); // INDIA (reference type is Bank)
Avoid this pattern. It is confusing and error-prone. Always access static fields via the class name, not an instance reference.
Can you put @Override on a static method?
No. The compiler explicitly rejects @Override on static methods because they cannot be overridden.
public class SavingsBank extends Bank {
// @Override // COMPILE ERROR: method does not override a superclass method
public static String getType() { return "SAVINGS"; }
}
How does this work with interface static methods?
Since Java 8, interfaces can have static methods. These are not inherited by implementing classes at all – they can only be called on the interface itself.
package com.bank.core;
import java.math.BigDecimal;
public interface InterestCalculator {
BigDecimal calculate(BigDecimal balance);
static BigDecimal defaultRate() {
return new BigDecimal("0.04");
}
}
public class SavingsInterest implements InterestCalculator {
@Override
public BigDecimal calculate(BigDecimal balance) {
return balance.multiply(InterestCalculator.defaultRate());
}
// SavingsInterest.defaultRate() does NOT compile
// Must use InterestCalculator.defaultRate()
}
This is different from static methods on classes, which are inherited (and can be hidden). Interface static methods are not inherited at all.
What are common mistakes?
- Assuming static methods are polymorphic.
parent.staticMethod()calls the parent's version, not the child's. This is the most common interview mistake. - Hiding static fields in subclasses. Creates two independent fields with the same name – deeply confusing.
- Using @Override on static. It does not compile.
- Calling static methods on instance references.
account.getType()compiles but resolves to the reference type's version, misleading the reader.
What should a senior engineer know?
- Design implication: If you need polymorphic behavior, use instance methods. Static is the wrong tool for anything that needs to vary by subclass.
- Factory method pattern:
Account.create(type)is static and chooses the subclass internally. This is a design choice that uses static for the entry point but returns polymorphic instances. - In Spring, @Bean methods are instance methods on @Configuration classes, not static. Static @Bean methods exist but bypass the CGLIB proxy and lose inter-bean reference resolution.
- In banking at National Bank of India, Rajesh uses static factory methods like
Account.savings(id, balance)to create specific account types, but the methods they call internally are instance methods that support polymorphism.
Visual Overview
Instance method: overriding (runtime dispatch)
Bank b = new SavingsBank();
b.getName() → "Savings Division" (object type wins)
Static method: hiding (compile-time dispatch)
Bank b = new SavingsBank();
b.getType() → "GENERIC" (reference type wins)
Rule:
instance → polymorphic (object type)
static → NOT polymorphic (reference type)
Key Takeaway
Static methods and fields are hidden, not overridden. When a subclass defines a static method with the same signature as the parent, the call is resolved by the reference type at compile time, not by the object type at runtime. This means Bank b = new SavingsBank(); b.getType() calls Bank's version, not SavingsBank's.
This is fundamentally different from instance methods, which are resolved by the actual object type at runtime (polymorphism). If you need behavior that varies by subclass, use instance methods, not static.
One sentence to remember: static methods are hidden, not overridden – they are resolved by the reference type at compile time with no polymorphism.
---