Ch. 7 · Java

Java Generics Wildcards and PECS

Use ? extends T for producers and ? super T for consumers, and understand why List<String> is not a List<Object>.

~2 min readadvancedupdated Oct 5, 2026

Java generics are invariant: List<String> is not a subtype of List<Object>, even though String is an Object. Wildcards restore flexibility at the point of use, and the rule for choosing between them is PECS — producer extends, consumer super.

Before you start

You should be comfortable with generics and collections. This article explains wildcard variance; it assumes familiarity with List<T> and bounded type parameters.

Step-by-step walkthrough

Step 1: Producer extends

When a method only reads values out of a collection, accept ? extends T. A List<? extends Number> can be read into Number, and it accepts List<Integer>, List<Double> and so on, which a List<Number> parameter would reject.

Step 2: Consumer super

When a method only writes values into a collection, accept ? super T. A List<? super Integer> accepts an Integer, and it accepts List<Number> or List<Object>, which is what you want when the method only adds values.

Step 3: Know the restriction

You cannot add to a ? extends collection because the compiler does not know the exact element type; adding an Integer to a List<? extends Number> might violate a List<Double>. Conversely, reading from a ? super collection yields only Object. The wildcard you cannot use is the one that would be unsafe.

Worked scenario

The method reads numbers out of the list, so it uses extends.

static double sum(List<? extends Number> values) {
  double total = 0;
  for (Number n : values) {
    total += n.doubleValue();
  }
  return total;
}
java

Walk through the example

sum accepts List<Integer>, List<Double> and List<Long> because each is a List<? extends Number>. The loop reads each element as Number and calls doubleValue, which every subtype supports. Adding to values would be a compile error, which is exactly right for a read-only method.

Common mistake

Using List<Object> as a parameter for “any list”, which rejects List<String> and forces callers to copy. Another is trying to add to a ? extends list and working around the error with an unchecked cast, which reintroduces the unsafe write.

Verify the behavior

Call sum with lists of Integer, Double and Long and confirm all compile. Attempt to add an element inside sum and read the wildcard error. Write a consumer method with ? super and confirm it accepts a broader element type but returns only Object on read.

Interview exercise

Why does Collections.copy(List<? super T> dest, List<? extends T> src) use both wildcards?

Answer and reasoning

The destination is a consumer, so it must accept any list that can hold a T, which ? super T expresses. The source is a producer, so it can be any list whose elements are a T or a subtype, which ? extends T expresses. Using both wildcards makes the method maximally flexible while keeping the read and write sides safe.

Continue learning

Compare generic design in Java immutability design and Java records boundaries. Read the Oracle generics wildcard documentation and try the Java interview questions.

More in Java

read ✓Java · hard

Java Time Types and Zone-Aware Decisions

Java Time Types and Zone-Aware Decisions. Learn the reasoning, a practical example, common mistakes and an interview exercise.

~2 min readread →
read ✓Java · easy

Java ArrayList Capacity and Performance

Java ArrayList Capacity and Performance. Learn the reasoning, a practical example, common mistakes and an interview exercise.

~2 min readread →
read ✓Java · mid

Java Comparators and Ordered Collections

Java Comparators and Ordered Collections. Learn the reasoning, a practical example, common mistakes and an interview exercise.

~2 min readread →
esc