Bounded Wildcards in Java Generics
Introduction
In Java Generics, the wildcard symbol (?) represents an unknown type. While extremely useful, an unbounded wildcard <?> is often too restrictive or too permissive. To write flexible yet type-safe APIs, Java provides Bounded Wildcards.
By bounding a wildcard, you restrict the unknown type to either be a specific class/interface or its subclasses/superclasses.
Types of Bounded Wildcards
1. Upper Bounded Wildcards (<? extends T>)
- Meaning: Accepts any type that is
Tor a subclass ofT. - Use Case: Use this when you want to read from a generic structure.
- Behavior: The structure becomes essentially read-only. Because the exact subclass is unknown, Java prevents you from adding new elements to the collection (to ensure type safety), but guarantees that anything you read from it can be safely cast to
T.
// Can accept List<Number>, List<Integer>, List<Double>, etc.
public static void printNumbers(List<? extends Number> list) {
for (Number n : list) {
System.out.println(n); // Safe to read as Number
}
// list.add(10); // COMPILE ERROR: Cannot add to <? extends Number>
}
2. Lower Bounded Wildcards (<? super T>)
- Meaning: Accepts any type that is
Tor a superclass ofT. - Use Case: Use this when you want to write/add to a generic structure.
- Behavior: You can safely add instances of
T(or its subclasses) into the collection. However, reading from it is restricted because you don't know the exact superclass type; you can only guarantee that elements retrieved are of typeObject.
// Can accept List<Integer>, List<Number>, List<Object>
public static void addNumbers(List<? super Integer> list) {
list.add(10); // Safe to add Integer
list.add(20);
// Integer i = list.get(0); // COMPILE ERROR: Must cast, only Object is guaranteed
}
The Golden Rule: PECS (Producer Extends, Consumer Super)
Coined by Joshua Bloch in Effective Java, PECS is the ultimate mnemonic for deciding which wildcard to use:
- Producer Extends: If your collection produces data (you only read from it), use
? extends T. - Consumer Super: If your collection consumes data (you only write to it), use
? super T.
Quick Checklist
- Need to read? Use
? extends T. - Need to write? Use
? super T. - Need to do both? Do not use a wildcard. Use an exact type parameter (e.g.,
List<T>).