Memra

Wildcards and PECS: producer-extends, consumer-super

◈ 4 cards

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:

WildcardMeaningYou can…You cannot…
? extends Tupper-boundedread as Tadd (except null)
? super Tlower-boundedadd T subtypesread only as Object
?unboundedread as Objectadd 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.

argumentList<Number>List<? extendsNumber>List<? superInteger>List<Integer>noyesyesList<Double>noyesnoList<Number>yesyesyesList<Object>nonoyesWhich argument each parameter type accepts.
The first column is invariance: only List<Number> itself fits. Extends widens downward to the producers you read from, super widens upward to the consumers you write into.
NORMAL ~/memra/learn/java-from-zero/wildcards-and-pecs utf-8 LF