Contrast `<? extends T>` and `<? super T>`: what each allows for reading and writing, and how you decide which to use.
answer
- extends = read/producer; super = write/consumer
- extends reads T, can't add
- super adds T, reads Object
- PECS: Producer Extends, Consumer Super
- both read+write → plain T
basics
~20 s<? extends T> is for reading: you get T's out but can't add. <? super T> is for writing: you can add T's but reads come back only as Object. Read from it → extends; write into it → super.
solid answer
~40 sThe two bounded wildcards are mirror images. `<? extends T>` (upper bound, covariant) means "T or a subtype": you can safely **read** elements as T, but you **cannot add** anything except null, because the exact subtype is unknown. `<? super T>` (lower bound, contravariant) means "T or a supertype": you can safely **write** a T (or subtype) in, but **reads** come back only as Object. The choice follows PECS — Producer Extends, Consumer Super: if the parameter is a source you read from, use extends; if it is a destination you write to, use super; if you do both, use a plain T. This asymmetry exists because Java generics are invariant, and wildcards are the type-safe way to relax that in exactly one direction at a time.
go deeper
States the read/write difference: extends to read, super to write, and knows PECS as a phrase.
Explains the soundness behind each restriction and applies PECS to method parameters.
Designs APIs with the correct wildcard, handles the both-directions case with plain T, and avoids wildcard return types.
Relates use-site wildcards to declaration-site variance and reasons about API ergonomics and inference impact across a codebase.
## Why two wildcards exist Java generics are **invariant**: `List<Integer>` is neither a subtype nor a supertype of `List<Number>`. That keeps the type system sound but makes generic method parameters inflexible. **Bounded wildcards** relax invariance safely in one direction: - `<? extends T>` — **upper-bounded**, **covariant**: "some unknown subtype of T (or T itself)." - `<? super T>` — **lower-bounded**, **contravariant**: "some unknown supertype of T (or T itself)." ## Side-by-side behavior | | `List<? extends T>` | `List<? super T>` | |---|---|---| | Element type | unknown **subtype** of T | unknown **supertype** of T | | Read `get()` | returns **T** (safe) | returns **Object** only | | Write `add(x)` | **forbidden** (except null) | **allowed** for T and subtypes | | Role | **producer** (source) | **consumer** (sink) | | Variance | covariant | contravariant | ### Why extends can read but not write ```java List<? extends Number> nums = new ArrayList<Integer>(); Number n = nums.get(0); // OK — every element is at least a Number nums.add(3); // ERROR — list might be List<Integer>, but the value could violate the real subtype; compiler forbids all non-null adds ``` You can read because every element is guaranteed to be a Number. You can't write because the real list might be `List<Integer>` and the compiler can't prove an arbitrary Number fits. ### Why super can write but reads only Object ```java List<? super Integer> sink = new ArrayList<Number>(); sink.add(7); // OK — an Integer fits any supertype-of-Integer slot Object o = sink.get(0); // only Object — element type is an unknown supertype ``` ## How to choose: PECS **Producer Extends, Consumer Super.** - The parameter is a **producer** (you read T out of it) → `<? extends T>`. - The parameter is a **consumer** (you write T into it) → `<? super T>`. - You **both** read and write it as T → use a plain `T` (no wildcard). Mnemonic example — the JDK copy method has one of each: ```java static <T> void copy(List<? super T> dest, List<? extends T> src); // consumer↑ producer↑ ``` ## Common gotchas - You can always add `null` to either, and you can always read into `Object` from either. - Don't use a wildcard on a return type — it leaks into every caller. - `<?>` (unbounded) is the special case `<? extends Object>`: read-only as Object, can't add anything but null. ## One-line decision rule Ask "does my method read T out of this, or put T into it?" Read → `extends`. Put → `super`. Both → exact `T`.
- Why can't you add elements to a `List<? extends Number>`?The actual list could be a `List<Integer>`, `List<Double>`, etc. The compiler doesn't know which, so it cannot guarantee any specific value (other than null) is the right subtype, and forbids adds.
- If a parameter is both read from and written to as T, which wildcard should you use?Neither — use the exact type `T`. Wildcards each sacrifice one direction; only a plain T supports both safe reads and safe writes.
saying these in an interview costs you the question
- Thinking you can add elements to a `<? extends T>` collection.
- Thinking you can read T (not Object) from a `<? super T>` collection.
- Using a wildcard when the method both reads and writes as T (use plain T).
- Believing `List<? extends Number>` and `List<Number>` are interchangeable.