Question 15 · Section 13

Can you inherit from an immutable class?

Technically — yes, if the class is not marked as final. But it's a bad idea, because a subclass can add mutable fields, and then code expecting an immutable object will get a mu...

Language versions: English Russian Ukrainian

Junior Level

Technically — yes, if the class is not marked as final. But it’s a bad idea, because a subclass can add mutable fields, and then code expecting an immutable object will get a mutable one.

Example of the problem

// "Immutable" class, but without final
public class ImmutableBase {
    private final String value;
    public ImmutableBase(String v) { this.value = v; }
    public String getValue() { return value; }
}

// Subclass adds mutability
public class MutableChild extends ImmutableBase {
    private String extra; // mutable field
    public void setExtra(String e) { this.extra = e; }
}

Solution

Always declare immutable classes as final:

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

Middle Level

Why inheritance breaks immutability

  1. New mutable fields — a subclass can add private String extra with a setter
  2. Overriding methods — a subclass can override getters, returning different data
  3. Unstable hashCode — immutable objects often cache hashCode; a subclass with mutable fields makes this cache invalid.

Alternatives to inheritance

1. Composition instead of inheritance

public final class ExtendedPoint {
    private final ImmutablePoint point;
    private final String label;
    // ...
}

2. Private constructors + static factories

public final class ImmutableObject {
    private final String data;
    private ImmutableObject(String data) { this.data = data; }
    public static ImmutableObject of(String data) { return new ImmutableObject(data); }
}

Examples from JDK

All fundamental immutable classes are final: String, Integer, BigDecimal, LocalDate.


Senior Level

Polymorphism as a threat

If a method expects ImmutableBase and relies on its immutability (e.g., caches a result based on getValue()), substituting MutableChild can lead to:

  • Invariant violation — data changes after validation
  • Security bypass — subclass returns different data after validation
  • Loss of thread-safety — subclass accesses non-final fields without synchronization

Sealed Classes (preview in Java 15, stable in Java 17)

If limited inheritance is needed:

public sealed class Shape permits Circle, Rectangle {
    // Both permitted classes must also be immutable
}

Summary for Senior

  • In most cases, inheriting from an immutable class is an anti-pattern. Exception: sealed class hierarchy (Java 17+), where all descendants are also immutable.
  • Always mark immutable classes as final
  • Immutability is not just final fields — it also means prohibiting logic changes through polymorphism
  • Use Sealed classes for controlled inheritance in Java 17+

Interview Cheat Sheet

Must know:

  • Technically possible (if not final), but it’s an anti-pattern — subclass adds mutability
  • Subclass can: add mutable fields, override getters, make hashCode unstable
  • Solution: always final class for immutable classes
  • Alternatives: composition instead of inheritance, sealed classes (Java 17+)
  • All fundamental JDK immutable classes are final: String, Integer, BigDecimal, LocalDate
  • Sealed classes allow limited inheritance with control over descendants

Frequent follow-up questions:

  • Why does inheritance break immutability? — Subclass adds mutable fields or overrides getters
  • What if I need to extend functionality? — Composition: wrap the immutable object in a new final class
  • Sealed classes vs final? — Sealed permits specific heirs, final prohibits all
  • Polymorphism as a threat? — Method relies on immutability, subclass swaps data after validation

Red flags (do NOT say):

  • “Inheriting from an immutable class is fine” — it’s an anti-pattern
  • “A subclass can’t change final fields” — true, but it can override getters
  • “Sealed classes = final” — sealed allows inheritance, but limited
  • “You can add a mutable field in a subclass” — that destroys the immutability contract

Related topics:

  • [[16. Why should an immutable class be final]]
  • [[17. What happens if you override getter in subclass of immutable class]]
  • [[3. How to create an immutable class in Java]]
  • [[7. What is the final keyword and how does it help create immutable classes]]