What does the wildcard `<? super T>` mean in Java generics, and what can you do with such a collection?
answer
- super = supertype = sink/consumer
- write T (and subtypes) in; read only Object out
- PECS: Consumer Super
- contravariance — subtype direction reversed
- Collections.copy dest is `<? super T>`
basics
~20 s<? super T> means "T or any of its parent types." You can safely add T (or its subtypes) to such a collection, but when you read from it you only get back Object, because you do not know the exact element type.
solid answer
~40 s`<? super T>` is a lower-bounded wildcard: the actual type argument is T or some supertype of T. Because every element is guaranteed to be at least a T (and possibly more general), it is safe to *write* a T or any subtype of T into the collection. Reading, however, is restricted: the compiler only knows each element is some unknown supertype of T, whose only guaranteed common ancestor is Object, so reads come back as Object. That makes a `<? super T>` reference a natural consumer or sink for T values. A classic example is `Collections.copy(List<? super T> dest, List<? extends T> src)`: the destination accepts T-or-subtype writes, the source supplies T-or-subtype reads.
go deeper
Can state that <? super T> means "T or a parent type" and that you write into it but read only Object.
Explains the write-safe / read-as-Object asymmetry and why invariance forces wildcards; knows PECS.
Connects it to contravariance, applies PECS correctly in API design, and cites Collections.copy / addAll signatures.
Frames use-site vs declaration-site variance, discusses API ergonomics and when over-using wildcards harms readability, and reasons about type-inference interactions.
## First principles: what a generic type and a wildcard are A **generic type** like `List<String>` is a type parameterized by another type. `List<E>` is the *declaration*; `List<String>` is an *instantiation* where the type argument `E` is fixed to `String`. Java generics are **invariant**: even though `Integer` is a subtype of `Number`, `List<Integer>` is **not** a subtype of `List<Number>`. This is deliberate — if it were allowed, you could put a `Double` into a `List<Number>` reference that actually points at a `List<Integer>`, corrupting it. A **wildcard** (`?`) is a way to relax invariance in a controlled, type-safe way. It says "some specific but unknown type." There are three forms: - `<?>` — unbounded: any type. - `<? extends T>` — **upper-bounded**: T or any *subtype* of T (a *producer* you read from). - `<? super T>` — **lower-bounded**: T or any *supertype* of T (a *consumer* you write to). This leaf. ## What `<? super T>` means `List<? super Integer>` means: a list whose element type is **Integer, or some ancestor of Integer** — e.g. `List<Integer>`, `List<Number>`, or `List<Object>`. The exact one is unknown at compile time; the compiler only knows it is *at least as general as* Integer. ## Why writes are safe (contravariance) Whatever the real element type is, it is a supertype of Integer. Therefore an `Integer` value (or any subtype of Integer) **is-a** instance of that element type, so storing it is always type-safe: ```java List<? super Integer> sink = new ArrayList<Number>(); sink.add(42); // OK: an Integer fits any supertype-of-Integer slot sink.add(Integer.valueOf(7)); // OK ``` You may add T and any **subtype** of T. You may **not** add a supertype of T (e.g. a `Number` that isn't an Integer), because the real list might be a `List<Integer>`. ## Why reads are limited (you only get Object) When you read an element, the compiler must give you a type that is valid no matter which supertype the list actually holds. The only type that *every* class is guaranteed to be assignable to is `Object`. So: ```java Object o = sink.get(0); // OK — best you can do Integer i = sink.get(0); // COMPILE ERROR ``` ## The PECS mnemonic Joshua Bloch's rule: **Producer Extends, Consumer Super.** If a parameter *produces* T values (you read T out of it), use `<? extends T>`. If it *consumes* T values (you write T into it), use `<? super T>`. A `<? super T>` parameter is a **consumer/sink**. ## Canonical example ```java public static <T> void copy(List<? super T> dest, List<? extends T> src) { for (int i = 0; i < src.size(); i++) dest.set(i, src.get(i)); // read T from src, write T into dest } ``` `dest` consumes T (super); `src` produces T (extends). This lets you copy a `List<Integer>` into a `List<Number>`. ## Relationship to variance theory `<? extends T>` introduces **covariance** (subtype direction preserved), `<? super T>` introduces **contravariance** (subtype direction reversed). Both are forms of *use-site variance* — variance declared at the point of use, unlike Kotlin/Scala's *declaration-site variance* (`in`/`out`).
- Why can you add a subtype of T but not a supertype of T to a `<? super T>` collection?Every element slot is guaranteed to hold at least a T, so a subtype of T (which is-a T) always fits. A supertype of T might not be a T, and the real list could be a `List<T>`, so adding it would be unsafe and is rejected.
- What is the single type you get back when reading from a `<? super T>` collection?Object — it is the only type every possible element is guaranteed to be assignable to.
saying these in an interview costs you the question
- Thinking `<? super T>` lets you read elements back as T (you only get Object).
- Believing you can add any supertype of T (you can only add T or its subtypes).
- Confusing it with `<? extends T>` — extends is the producer/read side.
- Assuming `List<? super Integer>` equals `List<Object>` — it is any of Integer/Number/Object.