Memra

Bounded type parameters: extends and multiple bounds

Restricting the types a parameter accepts with upper bounds and & for multiple constraints.

Restricting what T can be

An upper bound (T extends SomeType) constrains the allowed types and unlocks the methods of the bound:

// T must implement Comparable so we can call compareTo
public static <T extends Comparable<T>> T max(List<T> xs) {
    T result = xs.get(0);
    for (T item : xs) {
        if (item.compareTo(result) > 0) result = item;
    }
    return result;
}

max(List.of(3, 1, 4, 1, 5));  // Integer implements Comparable<Integer>
max(List.of("fig", "apple")); // String implements Comparable<String>

Without the bound the compiler would not allow item.compareTo(...) — it only knows T is Object.

extends means both extends and implements in a type-parameter context: <T extends Number> works for Integer, Double, BigDecimal, etc.

Multiple bounds use &. A class bound must come first, followed by interface bounds:

public <T extends Number & Comparable<T>> T clamp(T val, T lo, T hi) {
    if (val.compareTo(lo) < 0) return lo;
    if (val.compareTo(hi) > 0) return hi;
    return val;
}

The & bound list means T must satisfy all constraints simultaneously. You can have at most one class in a bound (since Java has single class inheritance) but as many interfaces as you need.

NORMAL ~/memra/learn/java-from-zero/bounded-type-parameters utf-8 LF