SyntaxStudy
Sign Up
Java Bounded Type Parameters
Java Beginner 1 min read

Bounded Type Parameters

Bounded type parameters restrict the types that can be used as type arguments. An upper-bounded wildcard () means T must be Number or a subclass of it, allowing you to call Number methods on instances of T. This is useful when you want to write a method that works with multiple related types while still being able to call common methods on them. You can combine bounds using & (e.g., & Cloneable>). Wildcards, denoted with ?, represent an unknown type. An upper-bounded wildcard (? extends Type) is used in method parameters when you only need to read from a collection. A lower-bounded wildcard (? super Type) is used when you only need to write to a collection. This is summarised by the PECS principle: Producer Extends, Consumer Super. Unbounded wildcards (?) are used when the method does not depend on the type at all, such as printing the size of any list. Understanding when to use type parameters versus wildcards is an important skill. Use a type parameter when there is a relationship between parameter types and the return type, or when the same type appears in multiple places. Use a wildcard when the method body does not depend on the specific type, making the API more flexible for callers.
Example
import java.util.List;
import java.util.ArrayList;

public class BoundedGenerics {

    // Upper bound: works with Number and its subclasses
    public static <T extends Number> double sumList(List<T> list) {
        double sum = 0;
        for (T item : list) {
            sum += item.doubleValue(); // Number method available
        }
        return sum;
    }

    // PECS: Producer Extends — read from source
    public static <T> void copy(List<? extends T> source,
                                List<? super T>   dest) {
        for (T item : source) {
            dest.add(item);
        }
    }

    // Unbounded wildcard — just needs to print
    public static void printAll(List<?> list) {
        for (Object o : list) {
            System.out.print(o + " ");
        }
        System.out.println();
    }

    public static void main(String[] args) {
        List<Integer> ints    = List.of(1, 2, 3, 4);
        List<Double>  doubles = List.of(1.5, 2.5, 3.0);

        System.out.println("Sum ints:    " + sumList(ints));
        System.out.println("Sum doubles: " + sumList(doubles));

        List<Number> numbers = new ArrayList<>();
        copy(ints, numbers);
        copy(doubles, numbers);
        System.out.print("Copied: ");
        printAll(numbers);
    }
}