Question 17 · Section 13

What happens if you override getter in subclass of immutable class?

If the immutable class is not final, a subclass can override a getter and return different data. This breaks all expectations of code that relies on immutability.

Language versions: English Russian Ukrainian

Junior Level

If the immutable class is not final, a subclass can override a getter and return different data. This breaks all expectations of code that relies on immutability.

public class ImmutableBase {  // not final — mistake
    private final String data;
    public ImmutableBase(String data) { this.data = data; }
    public String getData() { return data; }
}

public class MutableChild extends ImmutableBase {
    private String dynamicData;
    public void setDynamicData(String d) { this.dynamicData = d; }

    @Override
    public String getData() {
        // Note: the parent's final field data is still unchanged,
        // but getData() returns a different value.
        return dynamicData; // substituted result!
    }
}

Middle Level

Why this is dangerous

  1. Collection logic violation — if an object is in HashMap and its getter (used in equals()) returns different data — the object becomes impossible to find

  2. Security vulnerabilities — a security method checks getData() for forbidden characters, and the subclass substitutes the result after validation

  3. Loss of thread-safety — the subclass’s getter accesses non-final fields without synchronization → “dirty reads” in a multi-threaded environment

How to protect yourself

Always make immutable classes final:

public final class ImmutableBase { ... } // inheritance is impossible

Even with a final class, a getter can return a mutable object — this is another form of immutability violation, see file 29.


Senior Level

The deep problem

Overriding a getter destroys the immutability contract at the business logic level, even if final fields technically haven’t changed. The JMM guarantees visibility of final fields, but it cannot guarantee that a method will return exactly those fields.

Real-world example

public void authorize(ImmutableCredentials creds) {
    if (securityManager.check(creds.getToken())) {
        // Here a subclass can return a different token
        api.call(creds.getToken());
    }
}

Solution

  1. final class — completely prohibits inheritance
  2. sealed class (Java 17+) — allows only specific, verified heirs
  3. Composition — instead of inheritance

Summary for Senior

  • Overriding a getter destroys immutability guarantees through polymorphism
  • JMM does not protect against method logic substitution
  • Always final for immutable classes
  • sealed classes — for controlled inheritance

Interview Cheat Sheet

Must know:

  • A subclass can override a getter and return different data — immutability contract is broken
  • Collection logic violation: object in HashMap becomes unfoundable if getter participates in equals
  • Security vulnerabilities: getter substitutes result after validation (TOCTOU)
  • Loss of thread-safety: subclass getter accesses non-final fields without synchronization
  • JMM guarantees visibility of final fields, but not method logic
  • Solution: final class (full prohibition), sealed class (controlled inheritance), composition

Frequent follow-up questions:

  • Parent’s final fields haven’t changed — what’s the problem? — The getter returns DIFFERENT data, breaking the contract
  • Example of a real vulnerability? — authorize() checks the token, subclass returns a different token on save
  • How does JMM relate to this? — JMM protects final field data, but cannot guarantee the method will return exactly those
  • Does sealed class solve the problem? — Yes, if all permitted classes are also immutable

Red flags (do NOT say):

  • “Subclass getter is not dangerous — final fields are the same” — getter can return anything
  • “This is only a HashMap problem” — no, it’s security, thread-safety, and business logic
  • “You can test the getter” — polymorphism allows substitution at runtime
  • “Composition is always worse than inheritance” — for immutability, composition is the only safe path

Related topics:

  • [[15. Can you inherit from an immutable class]]
  • [[16. Why should an immutable class be final]]
  • [[7. What is the final keyword and how does it help create immutable classes]]
  • [[28. What happens if you modify a mutable key in HashMap]]