All topics
library
intermediate

Bounded Type Parameters & Wildcards

Know the difference between <T extends X>, <? extends X>, <? super X>, and PECS (Producer Extends, Consumer Super).

A bound restricts which types are allowed. A wildcard says you do not care about the exact type, only the direction.

extends = a vending machine (produces snacks — you can take items out but can't put your own in). super = a recycling bin (consumes items — you can put things in but what you get out is just 'Object').

Key Concepts

1
    <T extends Number>      a declaration: T must be a Number
    <? extends Number>      a use: some unknown subtype of Number
    <? super Integer>       a use: some unknown supertype of Integer
    <?>                     a use: some unknown type
2
extends lets you read.
    double sum(List<? extends Number> nums) {
      double t = 0;
      for (Number n : nums) t += n.doubleValue();    // reading is fine
      nums.add(1);                                   // will not compile
      return t;
    }
extends
3
You cannot add, because the list might be a List<Double> and your Integer would corrupt it. The compiler knows only that every element is a Number.
List<Double>IntegerNumber
4
super lets you write.
    void fill(List<? super Integer> dest) {
      dest.add(1);                    // fine -- Integer fits any supertype
      Integer i = dest.get(0);        // will not compile
    }
super
5
You can add an Integer, because the list holds Integer or something broader. Reading gives you Object, since that is all the compiler can guarantee.
IntegerObject
6
PECS: Producer Extends, Consumer Super. If the parameter gives you values, use extends. If it takes values from you, use super.
extendssuper
7
    static <T> void copy(List<? super T> dest, List<? extends T> src)
8
src produces, so extends. dest consumes, so super. That one signature is the whole rule.
srcextendsdestsuper
9
<?> is the read-only case. You can read Object and write nothing but null — useful for a method that only needs the size or wants to print the contents.
<?>Objectnull
10
Why any of this is needed. Generics are invariant: List<String> is not a List<Object>, even though a String is an Object. Wildcards are how you get the flexibility back without the hole that invariance closed.
List<String>List<Object>StringObject
11
The bound can also be multiple:
    <T extends Number & Comparable<T>>
12
Class first, then interfaces.
13
What the interviewer is probing.1. "What does PECS stand for and when do you apply it?" Probing: whether you can use it, not recite it. Stalls: "Producer extends, consumer super." Moves up: the application: a parameter you read from takes extends, one you write to takes super — Collections.copy(List<? super T> dest, List<? extends T> src).
14
2. "Why can you not add to a List<? extends Number>?" Probing: why extends is read-only. Stalls: "You should be able to, Integer is a Number." Moves up: the list might be a List<Double>, and the compiler only knows every element is a Number, not which subtype it accepts.
15
3. "What can you read out of a List<? super Integer>?" Probing: the other half of the rule. Stalls: "Integers." Moves up: Object — the list holds Integer or something broader, so Object is all the compiler can guarantee.
16
4. "What is the difference between <T extends Number> and <? extends Number>?" Probing: declaration site versus use site. Stalls: "They are the same." Moves up: the first declares a type parameter you can refer to by name; the second is a wildcard at a use site where you do not need to name the type.