Self-types and Class tokens
Recursive generics for fluent subclass APIs, and Class<T> tokens carrying types through erasure.
Recursive generics (the CRTP idiom) make fluent APIs return the subclass type:
abstract static class Node<Self extends Node<Self>> {
private final List<String> labels = new ArrayList<>();
@SuppressWarnings("unchecked")
public Self label(String l) { labels.add(l); return (Self) this; }
}
static class Task extends Node<Task> { }
new Task().label("a").label("b") stays a Task โ every link in the chain
returns Self. The cast (Self) this is safe by convention: the subclass
promises Self is itself. Its known cost: self-types do not survive
re-parenting โ Job extends Task cannot also be Node<Job>; a class has
one generic parent.
Class tokens: generics are erased, but a Class<T> object is the
runtime type. type.cast(value) and type.isInstance(value) turn erased
storage into checked retrieval โ the foundation of type-safe registries,
DI containers, and JSON binders. Where erasure loses the type, an explicit
token carries it.