Fragile base class problem in Java inheritance
Fast recall
Quick revision
Core answer
Interview-ready guide
Interview answer
The fragile base class problem is the risk that a subclass depends on more than the base class's normal public result. It may rely on a protected method, an overridable self-call, or the order of internal steps. A parent refactor can preserve its caller-facing behavior and still break that subclass.
For example, a counting collection may override add and addAll. If the base implementation changes from bulk storage to implementing addAll by repeatedly calling the overridable add, the subclass can count each value twice. The fix is not simply 'make every base abstract or final.' I would define and document supported hooks, avoid calling overridable methods from sensitive internals, make unsafe operations final, test supported subclasses, or use a composed delegate when I only wanted reuse.
Fragile base class problem in Java inheritance
Direct Answer
The fragile base class problem occurs when a change that preserves a base class's ordinary public behavior breaks a subclass that relied on an overridable method, protected state, call order, or another extension detail. It is a risk of implementation inheritance, not proof that every parent refactor or every inheritance design will fail.
Code Example
class Bag {
protected final List<String> values = new ArrayList<>();
public void add(String value) { values.add(value); }
// Version 1: bulk operation writes directly.
public void addAll(List<String> input) { values.addAll(input); }
}
class CountingBag extends Bag {
private int added;
@Override public void add(String value) {
added++;
super.add(value);
}
@Override public void addAll(List<String> input) {
added += input.size();
super.addAll(input);
}
}
If Bag.addAll is later refactored to for (String value : input) add(value);, normal Bag results are unchanged, but CountingBag.addAll counts once in its own override and again through the overridable add calls.
Common Mistakes & Pitfalls
- Using a non-breaking public signature as the only test: subclass extension behavior may still change.
- Showing a refactor that does not actually bypass or duplicate the override: trace dynamic dispatch step by step.
- Calling inheritance an encapsulation violation in every case: the issue is an undocumented or unstable extension surface.
- Prescribing 'fully abstract or final' as the only choices: documented template methods and stable abstract bases are also valid.
- Assuming composition removes all change risk: callers still depend on the collaborator contract.
Check your understanding
Answer these without looking back at the article.
- How does composition avoid the fragile base class problem?
- What is defensive coding in the context of inheritance?
Looking for a structured roadmap?
Every module on this page is also part of the full Java backend interview track.