Generics

Wildcards & PECS

Generic types are invariant — a List<Manager> is not a List<Employee>. Wildcards restore flexibility at API boundaries: ? extends T for inputs you read from (producers), ? super T for outputs you write to (consumers).
  • PECS: Producer → extends, Consumer → super (EJ 31)
  • From a List<? extends T> you can only read T's — adds are rejected
  • Into a List<? super T> you can only write T's — reads give Object
  • Wildcards belong in method signatures, not return types or fields
  • Unbounded <?>: "some specific type, unknown here" — read-only, null-add-only
Invariance and the fix
List<Manager> managers = List.of(boss);
// List<Employee> staff = managers;              // compile error: invariant!
List<? extends Employee> staff = managers;       // OK: covariant VIEW

Employee e = staff.get(0);      // reading produces Employee — safe
// staff.add(new Employee());   // rejected: might be a List<Manager>!

The compiler's logic: staff might point at a List<Manager>, so inserting a plain Employee would poison it. Conversely List<? super Manager> might be a List<Object>, so reads only promise Object — but inserting a Manager is always safe. Producers you read from: extends. Consumers you write into: super.

PECS in a real signature (java.util.Collections)
public static <T> void copy(List<? super T> dest,     // consumer of T
                            List<? extends T> src) {  // producer of T
    for (int i = 0; i < src.size(); i++)
        dest.set(i, src.get(i));
}

// Callers get maximum flexibility:
List<Number> numbers = ...;
List<Integer> ints = ...;
Collections.copy(numbers, ints);   // Integer source into Number destination — natural
Sources
  • Core Java, Volume I: Fundamentals (13th ed.)Ch. 8.6–8.8 — Inheritance Rules; Wildcard Types
  • Effective Java (3rd ed.)Item 31