skip to content

What is the difference between an abstract primitive method and a hook method in Template Method, and how does the JDK use each?

level: middleimportance: should knowfreq 45%

answer

  1. Primitive = abstract = must implement
  2. Hook = default body = optional override
  3. Hooks give optional steps and veto control
  4. Minimize primitives, expose hooks
  5. LinkedHashMap.removeEldestEntry = LRU hook

basics

~20 s

A primitive is an abstract step the subclass must implement. A hook is a step with a default body in the base class, so overriding it is optional. The template method calls both; hooks let subclasses tweak behavior without being forced to.

solid answer

~50 s

In Template Method the base class's template method calls two kinds of step. **Primitive (abstract) methods** have no body — they are declared abstract, so every concrete subclass is forced to supply them; they represent the essential, must-vary parts of the algorithm. **Hook methods** ship with a default implementation (often empty, or a sensible no-op, or returning a default flag) — subclasses may override them to influence the algorithm but are not required to. Hooks are how the base class offers *optional* extension points and lets subclasses veto or augment steps. In the JDK, AbstractList.get/size are primitives. A classic hook is the protected step seen in skeletal classes, or AbstractQueue building concrete add/remove/element on the queue's abstract offer/poll/peek. The guideline is: make a method abstract when every subclass must answer it; make it a hook when most subclasses are fine with the default.

go deeper

for a junior

Knows abstract methods must be implemented and that some base-class methods have defaults you can optionally override.

for a middle

Clearly separates primitives (abstract, required) from hooks (default body, optional) and can give an example of each.

for a senior

Explains hook purposes (optional step, veto flag, default override), cites LinkedHashMap.removeEldestEntry, and the 'minimize primitives' design rule.

for a principal

Discusses how primitives and hooks form a published contract for subclassers, documentation obligations for self-use, and the maintenance cost of protected extension points across versions.

## Two kinds of step A template method runs a sequence of steps. Those steps fall into two categories: ### 1. Primitive (abstract) methods - **Definition:** declared `abstract` in the base class — *no body*. - **Effect:** the Java compiler refuses to let a concrete subclass exist unless it implements them. - **Meaning:** "this step has no sensible default; you *must* tell me how it works." - **Example:** `AbstractList.get(int)` and `AbstractList.size()` — there is no default way to fetch an element or know the length; the subclass owns the data, so it must answer. ### 2. Hook methods - **Definition:** a `protected` (or public) method with a **default implementation** in the base class — often empty, a no-op, a default constant, or a boolean flag. - **Effect:** the subclass *may* override it but is **not required** to. - **Meaning:** "here is a reasonable default; override only if you want to change this aspect." - **Purposes of hooks:** - **Optional behavior:** an empty `protected void beforeStep() {}` that does nothing unless overridden. - **Conditional control:** a `protected boolean shouldDoX() { return true; }` the template consults to decide whether to run an optional step (letting a subclass *veto* it). - **Default with override:** `header()`/`footer()` in a report builder that have sensible defaults but can be customized. ## Why the distinction matters - **Forcing vs. offering:** abstract = forced contribution; hook = offered extension point. Over-using abstract methods makes the class painful to subclass (every subclass must implement many methods even when it doesn't care). Over-using hooks can hide required behavior behind silent defaults. - **Design rule (from GoF / Effective Java):** *minimize the number of primitives* a subclass must implement, and *expose hooks* for the optional variation. Document for each non-final method whether overriding it is required, optional, or forbidden. ## A worked example ```java abstract class DataExporter { public final void export(List<Row> rows) { // template method open(); if (includeHeader()) writeHeader(); // hook decides for (Row r : rows) writeRow(format(r)); // primitive: format close(); } protected void open() {} // hook (no-op default) protected boolean includeHeader() { return true; }// hook (overridable flag) protected void writeHeader() {} // hook protected abstract String format(Row r); // primitive (required) protected abstract void writeRow(String line); // primitive (required) protected void close() {} // hook } ``` A `CsvExporter` *must* implement `format` and `writeRow` (primitives) but can ignore `open`, `close`, and `includeHeader` (hooks) unless it needs them. ## In the JDK - **Primitives:** `AbstractList.get/size`, `AbstractMap`'s `entrySet()`, `AbstractQueue`'s reliance on the queue's `offer`/`poll`/`peek`. - **Hooks / defaults that subclasses may override:** `AbstractList.set/add/remove` ship as throwing defaults — a subclass overrides them only to gain mutability; `AbstractCollection` provides default `toArray`, `contains`, `isEmpty` that you may override for performance but need not. - **Veto-style hook:** `LinkedHashMap.removeEldestEntry()` returns `false` by default, and overriding it to return `true` turns the map into an LRU cache. That is a hook controlling an optional step (eviction) in `put`'s template flow. ## Summary | | Primitive (abstract) | Hook | |---|---|---| | Has a body in base? | No | Yes (default) | | Subclass must override? | Yes | No | | Represents | essential variation | optional variation / control | | JDK example | AbstractList.get/size | LinkedHashMap.removeEldestEntry |

  • Give a JDK hook whose override changes an optional step, and what overriding it achieves.
    LinkedHashMap.removeEldestEntry returns false by default; overriding it to return true (e.g. when size exceeds a cap) makes the map evict its oldest entry on put — turning it into an LRU cache.
  • Why prefer fewer primitive methods in a skeletal class?
    Each primitive is a method every concrete subclass is forced to implement. Fewer primitives lower the burden and the chance of an inconsistent implementation; optional variation is better expressed as overridable hooks with sensible defaults.

saying these in an interview costs you the question

  • Calling every overridable method a 'hook' — a hook specifically has a default body; an abstract method is a primitive.
  • Saying hooks must be overridden — by definition they are optional.
  • Treating the distinction as cosmetic; it changes whether the compiler forces an implementation and how easy the class is to subclass.

context