Memra

Wildcards and PECS: producer-extends, consumer-super

The three wildcard forms, why you cannot add to ? extends T, and the PECS rule.

The problem with co-assignment

You might expect List<Number> to accept a List<Integer> since Integer extends Number. It does not:

List<Integer> ints = List.of(1, 2, 3);
List<Number>  nums = ints; // compile error — not assignable

Generics are invariant by default. This is intentional: if the assignment were allowed you could add a Double through nums and corrupt the Integer list.

Wildcards let you loosen that rigidity:

| Wildcard | Meaning | You can… | You cannot… | |---|---|---|---| | ? extends T | upper-bounded | read as T | add (except null) | | ? super T | lower-bounded | add T subtypes | read only as Object | | ? | unbounded | read as Object | add anything |

### Upper-bounded: ? extends T — Producer Extends

public static double sum(List<? extends Number> list) {
    double total = 0;
    for (Number n : list) total += n.doubleValue();
    return total;
}
sum(new ArrayList<Integer>()); // OK
sum(new ArrayList<Double>());  // OK

You can read elements as Number. You cannot add (except null) because the compiler doesn't know the actual element type — it could be List<Integer> where a Double would be illegal.

### Lower-bounded: ? super T — Consumer Super

public static void addIntegers(List<? super Integer> sink) {
    sink.add(1);
    sink.add(2);
    sink.add(3);
}
addIntegers(new ArrayList<Number>());  // OK
addIntegers(new ArrayList<Object>());  // OK

You can add Integer values because whatever the actual type is, it's guaranteed to be a supertype of Integer. Reading back gives you only Object — the lower bound gives no useful upper constraint.

### The PECS mnemonic

Producer Extends, Consumer Super — when a data source *produces* values you read, use ? extends T. When a data sink *consumes* values you write, use ? super T.

NORMAL ~/memra/learn/java-from-zero/wildcards-and-pecs utf-8 LF