What is the difference between an abstract primitive method and a hook method in Template Method, and how does the JDK use each?
answer
- Primitive = abstract = must implement
- Hook = default body = optional override
- Hooks give optional steps and veto control
- Minimize primitives, expose hooks
- LinkedHashMap.removeEldestEntry = LRU hook
basics
~20 sA 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 sIn 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
Knows abstract methods must be implemented and that some base-class methods have defaults you can optionally override.
Clearly separates primitives (abstract, required) from hooks (default body, optional) and can give an example of each.
Explains hook purposes (optional step, veto flag, default override), cites LinkedHashMap.removeEldestEntry, and the 'minimize primitives' design rule.
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.