skip to content

Lower-Bounded Wildcard

<? super T> lets you write T and its subtypes in, but reads come back only as Object. Consumers use this form, the second half of PECS.

part ofJavaoverview, primer and where to startread it →
on this pageshow

questions

5

Contrast `<? extends T>` and `<? super T>`: what each allows for reading and writing, and how you decide which to use.

level: juniorimportance: must knowfreq 66%

answer

  1. extends = read/producer; super = write/consumer
  2. extends reads T, can't add
  3. super adds T, reads Object
  4. PECS: Producer Extends, Consumer Super
  5. 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 s

The 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

for a junior

States the read/write difference: extends to read, super to write, and knows PECS as a phrase.

for a middle

Explains the soundness behind each restriction and applies PECS to method parameters.

for a senior

Designs APIs with the correct wildcard, handles the both-directions case with plain T, and avoids wildcard return types.

for a principal

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.

context

open as a page

What does the wildcard `<? super T>` mean in Java generics, and what can you do with such a collection?

level: middleimportance: must knowfreq 70%

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.

open as a page

Why can you only read elements as `Object` from a `List<? super T>`, and what is the underlying type-safety reasoning?

level: middleimportance: should knowfreq 48%

basics

~20 s

Because the list's real element type could be T or any of its parents, the compiler doesn't know the exact type. The only type guaranteed to fit every possibility is Object, so reads come back as Object.

open as a page

Why does `Comparator<? super T>` appear in signatures like `Collections.sort` and `Stream.sorted`, and what flexibility does it give callers?

level: seniorimportance: should knowfreq 40%

basics

~20 s

A comparator that knows how to compare T's supertype can also compare T's, since every T is-a supertype. Accepting Comparator<? super T> lets you reuse one general comparator (e.g. for Animal) to sort a list of a subtype (e.g. Dog).

open as a page

Explain the PECS rule and why a method that copies elements into a destination should declare it as `List<? super T>`.

level: seniorimportance: should knowfreq 62%

basics

~20 s

PECS means "Producer Extends, Consumer Super." Something you read from uses extends; something you write to uses super. A copy destination is written to (a consumer), so it should be List<? super T> to accept T and its subtypes.

open as a page