Explain the curiously recurring generic pattern (CRGP) in Java and give a use case for it.
answer
- class X<T extends X<T>>, subclass extends X<Subclass>
- Lets base methods return the concrete subtype
- self() = (T) this, unchecked cast
- Flagship use: inheritable fluent builders
- Convention only — wrong-type subclass still compiles
basics
~20 sA class declares itself as its own type parameter, like 'class Node<T extends Node<T>>'. Subclasses pass themselves in. It lets base-class methods refer to the actual subclass type — useful for fluent builders that return the right subtype.
solid answer
~50 sThe curiously recurring generic pattern (CRGP, the Java analogue of C++'s CRTP) is a class declared with a self-referential bound where subclasses parameterize the base with themselves: 'class AbstractBuilder<T extends AbstractBuilder<T>>' and 'class ConcreteBuilder extends AbstractBuilder<ConcreteBuilder>'. This lets methods in the base class know the concrete subtype T, so they can return T instead of the base type. The classic use is a fluent builder hierarchy: a shared base defines common setters that return 'self()' typed as T, so chaining preserves the concrete builder type and you can still call subclass-specific methods after a base setter. Other uses include self-typed comparable/entity hierarchies and generic DSLs. The catch is that nothing forces a subclass to pass its own type — 'class Evil extends AbstractBuilder<SomethingElse>' compiles — so it's a convention, not an ironclad guarantee, usually paired with an abstract 'T self();' implemented as 'return this;'.
code
java · 14 linesabstract class Builder<T extends Builder<T>> {
@SuppressWarnings("unchecked")
protected T self() { return (T) this; }
T common(String v) { /* set field */ return self(); }
}
class UserBuilder extends Builder<UserBuilder> {
UserBuilder name(String n) { /* ... */ return this; }
}
// Chaining preserves the concrete type:
UserBuilder b = new UserBuilder()
.common("x") // returns UserBuilder, not Builder
.name("Ann"); // subclass method still reachablego deeper
Recognizes the unusual 'class X<T extends X<T>>' shape and that it relates to builders, even if the why is fuzzy.
Explains it makes base methods return the concrete subtype and can sketch a fluent-builder example.
Implements it correctly with self()/abstract self(), names real-world users, and explains it's convention-not-guarantee with the unchecked cast.
Weighs the API ergonomics cost (signature noise, leaky generic) vs. benefit, knows when to avoid it, and relates it to CRTP and true self-types in other languages.
## The problem CRGP solves Suppose you have a base class with methods that should return the *most specific* subtype so callers can keep chaining. A non-generic base can only return its own type: ```java class Animal { Animal eat() { ...; return this; } } class Dog extends Animal { Dog bark() { ...; return this; } } new Dog().eat().bark(); // COMPILE ERROR: eat() returns Animal, which has no bark() ``` The base method `eat()` returns `Animal`, so the static type after `.eat()` is `Animal`, and `Animal` has no `bark()`. We want `eat()` to return `Dog` when called on a `Dog`. ## The pattern **Curiously Recurring Generic Pattern (CRGP)** — also called the **self-type idiom**, and the Java cousin of C++'s **CRTP** (Curiously Recurring Template Pattern) — solves this by making the base generic over a type that *is itself*: ```java abstract class Animal<T extends Animal<T>> { @SuppressWarnings("unchecked") protected T self() { return (T) this; } T eat() { /* ... */ return self(); } } class Dog extends Animal<Dog> { // passes itself as T Dog bark() { /* ... */ return this; } } new Dog().eat().bark(); // OK: eat() returns Dog ``` Read the bound `<T extends Animal<T>>` as: "T is some subtype of Animal that is parameterized by itself." When `Dog extends Animal<Dog>`, inside `Animal` the placeholder `T` *is* `Dog`, so `eat()` returns `Dog`. ## Why `self()`? Inside the base you have `this`, whose static type is `Animal<T>`, not `T`. You can't return `this` directly where `T` is expected, so you cast: `(T) this`. That cast is unchecked (the compiler can't verify the subclass actually passed itself), hence `@SuppressWarnings`. A common cleaner variant declares `protected abstract T self();` and each leaf implements `return this;`, moving the (now safe) cast out of the base. ## The canonical use case: fluent builders ```java abstract class PizzaBuilder<T extends PizzaBuilder<T>> { protected final List<String> toppings = new ArrayList<>(); @SuppressWarnings("unchecked") protected T self() { return (T) this; } T addTopping(String t) { toppings.add(t); return self(); } } class DeluxePizzaBuilder extends PizzaBuilder<DeluxePizzaBuilder> { DeluxePizzaBuilder stuffedCrust() { /* ... */ return this; } } new DeluxePizzaBuilder() .addTopping("cheese") // returns DeluxePizzaBuilder, not PizzaBuilder .stuffedCrust() // subclass method still reachable .addTopping("olives"); ``` Without CRGP, `addTopping` would return the base type and `.stuffedCrust()` would be unreachable in the chain. CRGP is the standard way to build inheritable fluent APIs (Spring Security, AssertJ, jOOQ use this shape). ## Limits and gotchas 1. **It's a convention, not a guarantee.** `class Liar extends Animal<Dog>` compiles even though `Liar` is not `Dog`; `self()` would then throw `ClassCastException`. The bound prevents passing a *non-Animal*, but not passing the *wrong* Animal. 2. **The unchecked cast** is inherent; document it. 3. **Type-signature noise** — every consumer of the hierarchy sees the `<T>` parameter, which hurts readability. For a single-level builder you don't need it at all. 4. **No true `self` type in Java.** Languages like Scala/Swift have a real `Self` type; CRGP is the workaround. Erasure means it's purely compile-time machinery. ## Summary CRGP = a class parameterized by a self-referential bound (`X<T extends X<T>>`) with subclasses passing themselves, so base methods can speak in terms of the concrete subtype. The flagship application is inheritable fluent builders; the price is an unchecked self-cast and a subtype contract enforced only by convention.
- How does CRGP differ from C++'s CRTP?CRTP uses templates resolved at compile time to enable static polymorphism (the base can call subclass methods with no virtual dispatch). Java CRGP is about type-level self-reference for return types; Java still uses normal virtual dispatch and erases the generics, so there's no static-polymorphism performance angle.
- Why is the self() cast unchecked and can it ever fail?Because the compiler can't verify the subclass parameterized the base with its own type. It fails with ClassCastException only if a subclass lies (extends X<SomethingElse>). With the disciplined convention it never fires.
saying these in an interview costs you the question
- Claiming the bound forces a subclass to pass its own type (it doesn't — Liar extends X<Other> compiles)
- Saying it works at runtime via reflection — it's pure compile-time, generics are erased
- Confusing it with simple bounded generics; CRGP specifically self-parameterizes the class
- Using it for a one-level builder where it adds noise for no benefit