Java 15: Bounded Type Parameters
easy⏱ 5 mincoursejava
Upper bounds
<T extends Number> — T must be Number or a subtype. Inside the method you can call Number methods on T. Multiple bounds: <T extends Number & Comparable<T>> — the first must be a class (or none), the rest are interfaces. Fewer than 1% of Java code uses multi-bound, but it's legal.
public static <T extends Number> double sum(List<T> nums) {
double total = 0;
for (T n : nums) total += n.doubleValue(); // Number method
return total;
}
Self-bounded type (F-bound)
<T extends Comparable<T>> reads: 'T is comparable to itself'. This rules out weird cases like Integer being comparable to String. You'll see the same pattern in Enum<E extends Enum<E>> — the self-bound is how Java makes enum operations type-safe without casts.
// From java.lang.Enum — the archetypal F-bound
public abstract class Enum<E extends Enum<E>> implements Comparable<E>, Serializable {
public final int compareTo(E o) { ... }
}
Build a bounded max
Write max<T extends Comparable<T>>(items: T[]): T. For each element, call compareTo on the running max. Test with numbers (TS number doesn't implement Comparable, so wrap in a ComparableNumber class). Also test with a Semver class that compares by major.minor.patch.
Lower bounds for type parameters don't exist
Java allows <T extends X> (upper bound) but not <T super X> (lower bound). Lower bounds only exist for wildcards (? super X). If you need lower-bound-like behavior on a type parameter, you usually want a wildcard instead.
Quiz: Why F-bound in Enum
Why does Enum use E extends Enum<E> and not just Enum<E>? To guarantee compareTo(E) only compares values of the same enum class. Without the self-bound, the compiler would allow Color.RED.compareTo(Size.LARGE) — a nonsense comparison across enum types.