Why can you not add elements (other than null) to a List<?>, but you can still read from it?
answer
- ? captured as one unknown type CAP#1
- add needs a value provable as CAP#1 - none exists
- null is a member of every reference type
- get returns CAP#1, always an Object
- Producer-only (PECS: extends = producer)
basics
~20 sThe compiler doesn't know the real element type behind ?, so it can't be sure any value you add fits - except null, which fits every type. Reading is fine because whatever comes out is at least an Object.
solid answer
~40 sWith List<?> the element type is a single, unknown, specific type - call it CAP#1 (the compiler's 'capture' of the wildcard). To allow add(x), the compiler must prove x is of type CAP#1. Since CAP#1 is unknown, it can prove this for no value at all - except null, which is assignable to every reference type. So every add is rejected except add(null). Reading is the mirror image: get() returns CAP#1, and whatever CAP#1 is, it is guaranteed to be an Object. So you can always read into an Object variable. This is the get/put asymmetry: an unbounded (or upper-bounded) wildcard is effectively a producer you can read from but not write to. If you need to write, you need a concrete type parameter or a lower-bounded wildcard like List<? super T>.
go deeper
Knows you can read List<?> as Object and can only add null.
Explains the restriction via 'one unknown type' and that null is a member of every reference type.
Frames it with wildcard capture (CAP#1) and the producer/consumer (PECS) model, and knows the write-enabling alternative is ? super T.
Reasons about soundness guarantees the rule enforces and applies the producer/consumer distinction to API design across a codebase.
## The core idea: one unknown type, not 'any type' `List<?>` does **not** mean 'a list that can hold any type'. It means 'a list whose element type is **one specific type that we don't know**'. The compiler internally gives that unknown type a fresh name - this is called **wildcard capture**, often shown in errors as something like `CAP#1`. ## Why `add` is (almost) forbidden Consider `void f(List<?> list)`. Inside, suppose you try `list.add("hello")`. The actual list passed in might be: ``` f(new ArrayList<Integer>()); // ? is Integer ``` Now `list.add("hello")` would put a `String` into a `List<Integer>` - heap corruption. The compiler has no way to know which type was passed, so to stay **sound** (never allow a bad value in), it rejects `add` for *every* concrete value. The signature of `add` becomes effectively `add(CAP#1 e)`, and you have no value you can prove is a `CAP#1`... ## ...except `null` `null` is the one value that is a legal member of **every** reference type. `CAP#1`, whatever it is, is a reference type, so `null` is always a valid `CAP#1`. Therefore `list.add(null)` compiles. It is the single exception. ## Why reading always works `E get(int i)` becomes effectively `CAP#1 get(int i)`. You don't know what `CAP#1` is, but you know one thing for certain: it is a reference type, so it **is an Object**. Hence: ``` Object o = list.get(0); // always OK ``` You simply cannot assign the result to anything more specific than `Object`, because you can't prove it is, say, a `String`. ## The mental model: producer vs consumer An unbounded wildcard (and an upper-bounded one, `? extends T`) makes the collection a **producer**: you can take things *out* (read) but not put things *in* (write). This is half of the **PECS** rule - *Producer Extends, Consumer Super*. To consume (write into) a collection you need `? super T` or a concrete type. `List<?>` is the most extreme producer-only form: you can only read elements as `Object`. ## Practical consequence Methods that take `List<?>` advertise 'I will not modify your list's contents'. That makes them safe to call with a list of any element type, which is exactly the flexibility the wildcard buys.
- What is wildcard capture?It is the compiler giving the unknown wildcard type a fresh, named type variable (e.g. CAP#1) so it can reason about it; it appears in compiler error messages and underlies the add/get rules.
- How does this relate to ? extends T versus ? super T?? extends T and unbounded ? are producers (read-only, by PECS 'extends'); ? super T is a consumer you can write T into. The unbounded wildcard behaves like the read-only producer side.
saying these in an interview costs you the question
- Saying ? means 'any type', so anything can be added - it means one unknown type
- Believing you cannot read at all from List<?> - you can, as Object
- Forgetting that null is the allowed exception to the add rule
- Confusing this with List<? super T>, which DOES allow writing T