Bounded Types

extends in Type Parameters

<T extends Number> means "T must be Number or a subclass". Inside the method you can then call Number methods like doubleValue(). For interfaces you also write extends: <T extends Comparable<T>>.

Example

import java.util.List;

public class Main {
    static <T extends Number> double sum(List<T> nums) {
        double total = 0;
        for (T n : nums) total += n.doubleValue();
        return total;
    }

    static <T extends Comparable<T>> T max(List<T> items) {
        T best = items.get(0);
        for (T item : items) {
            if (item.compareTo(best) > 0) best = item;
        }
        return best;
    }

    public static void main(String[] args) {
        System.out.println(sum(List.of(1, 2, 3)));
        System.out.println(sum(List.of(2.5, 4.5)));
        System.out.println(max(List.of(17, 42, 8)));
        System.out.println(max(List.of("mango", "apple", "zucchini")));
        // sum(List.of("a", "b"));   // compile error: String is not a Number
    }
}

Output

6.0
7.0
42
zucchini

Multiple Bounds

// T must extend Number AND implement Comparable<T> (class first, then interfaces)
static <T extends Number & Comparable<T>> T clamp(T value, T min, T max) {
    if (value.compareTo(min) < 0) return min;
    if (value.compareTo(max) > 0) return max;
    return value;
}