skip to content

Why can't you add elements (other than null) to a `List<? extends Number>`?

level: juniorimportance: should knowfreq 58%

answer

  1. ? extends = unknown single subtype
  2. compiler can't prove your value fits
  3. only null is addable
  4. reads are safe (at least Number)
  5. prevents heap pollution

basics

~20 s

Because the real list could be a List<Integer>, a List<Double>, or any subtype of Number — the compiler does not know which. It cannot prove your value fits, so it blocks adds. Only null is always safe.

solid answer

~40 s

`List<? extends Number>` means "a list of some single unknown subtype of Number." The compiler does not know whether the real list is `List<Integer>`, `List<Double>`, or `List<Number>`. If it let you add a `Double` and the list was actually a `List<Integer>`, you would corrupt it — breaking the very type safety generics exist to guarantee. So adding any typed element is rejected at compile time. The one exception is `null`, which is a valid value of every reference type, so it is always safe. Reading, by contrast, is fine: whatever the element really is, it is guaranteed to be at least a Number. This read-only-for-producers behavior is exactly the "Extends" half of PECS.

code

java · 4 lines
java
List<? extends Number> nums = List.of(1, 2, 3); // really a List<Integer>
Number n = nums.get(0); // OK: read is safe
// nums.add(4);         // compile error: cannot prove 4 fits
nums = null;             // (reassignment) — and the only addable value is null itself

go deeper

for a junior

Explains that the real type is unknown so the compiler blocks adds, and that only null is allowed.

for a middle

Articulates the heap-pollution scenario and ties the restriction to generic invariance and the producer role.

for a senior

Reasons about it formally (assignability to the unknown element type) and uses it to justify API parameter choices.

for a principal

Uses this to frame variance guidance for the team and to evaluate the safety of library signatures and migration risks.

## What the wildcard actually means Write `List<? extends Number>`. The `?` is a **wildcard** — it stands for *one specific but unknown* type. The bound `extends Number` says that unknown type is Number itself or some subtype of Number. So the variable might be bound, at runtime, to a `List<Integer>`, a `List<Double>`, a `List<Number>`, or any other `List<X>` where `X` is a Number. The crucial word is **unknown**. The compiler picks no single type; it must keep the code safe for *every* possibility. ## Why adding is unsafe Suppose adding were allowed: ```java List<Integer> ints = new ArrayList<>(); List<? extends Number> nums = ints; // legal: List<Integer> is a List<? extends Number> nums.add(3.14); // imagine this compiled... Integer i = ints.get(0); // ...ClassCagstException at runtime! ``` If `nums.add(3.14)` compiled, we would have slipped a `Double` into a `List<Integer>`. Later `ints.get(0)` would return what it thinks is an `Integer` and blow up. Generics exist precisely to prevent this kind of *heap pollution*, so the compiler refuses the add up front. More formally: to add a value `v`, the compiler must prove `v` is assignable to the list's element type. But the element type is the unknown `?`. The only value assignable to *every* possible reference type is `null` — so `null` is the lone exception. ## Why reading is still fine Reading has the opposite logic. Whatever the unknown element type is, it is guaranteed to be Number or a subtype, so `Number n = nums.get(0);` is always safe — the result is at least a Number. A `? extends` list is therefore a **producer**: you can take values out but not put them in. ## Connection to PECS This is the "Producer Extends" half of the mnemonic. A `? extends T` collection produces T's (safe to read) and cannot consume them (unsafe to write). The mirror image is `? super T`: safe to write a T, but reads come back as `Object`. ## Terms defined - **Invariance:** `List<Integer>` is not a subtype of `List<Number>` despite `Integer` being a subtype of `Number`. Wildcards exist to work around this when it is safe. - **Heap pollution:** a situation where a variable of a parameterized type refers to an object whose actual element type differs, leading to runtime `ClassCastException`s. - **Bound:** the `extends Number` part that limits which types the `?` can be.

  • Is `null` really addable to a `List<? extends Number>`?
    Yes. `null` is a member of every reference type, so it is the single value the compiler can prove is always safe to add.
  • If you need to add real elements, what should the parameter type be instead?
    Use `List<? super Number>` (or a concrete `List<Number>`/`List<T>`) so the list is a consumer you can safely write into.

saying these in an interview costs you the question

  • Thinking you can add any Number subtype because the bound is Number
  • Believing the wildcard means "any mix of Number subtypes" (it is one unknown type)
  • Saying you cannot read either (reads are fine)
  • Forgetting that null is the one allowed add

context