Generics

Type Bounds

Bounds constrain type parameters so your code can actually call methods on them: <T extends Comparable<T>> promises order. Multiple bounds combine one class with any number of interfaces.
  • <T extends Bound> — T must be a subtype of Bound (class or interface, "extends" covers both)
  • Multiple bounds: <T extends Runnable & Comparable<T>>; the class (if any) comes first
  • Without a bound, T is implicitly Object — only Object's methods are callable
  • The recursive form <T extends Comparable<? super T>> is the production-grade signature
Why bounds exist
public static <T extends Comparable<T>> T min(T[] a) {
    T smallest = a[0];
    for (T x : a)
        if (x.compareTo(smallest) < 0) smallest = x;   // legal ONLY due to the bound
    return smallest;
}

Without extends Comparable<T>, the call x.compareTo(...) cannot compile — the compiler only knows T is an Object. The bound is both a restriction on callers and a capability inside the method.

The fully general form is <T extends Comparable<? super T>> — it accepts types whose superclass implements the comparison (e.g. java.sql.Timestamp extends java.util.Date, which implements Comparable<Date>). This "recursive type bound with a super wildcard" appears throughout java.util.Collections; the reasoning is pure PECS.

Sources
  • Core Java, Volume I: Fundamentals (13th ed.)Ch. 8.4 — Bounds for Type Variables
  • Effective Java (3rd ed.)Item 30