skip to content

What is the difference between a bounded type parameter <T extends Number> and an upper-bounded wildcard <? extends Number>, and when would you choose each?

level: seniorimportance: must knowfreq 55%

answer

  1. named T vs anonymous ?
  2. wildcard = read-only producer
  3. add only null to ? extends
  4. PECS: producer extends
  5. invariance: List<Integer> != List<Number>

basics

~20 s

A bounded type parameter <T extends Number> names a type you can reuse across the signature and return. A wildcard <? extends Number> is an anonymous unknown subtype used for a single parameter; you can read Numbers from it but generally cannot add to it.

solid answer

~50 s

<T extends Number> introduces a named type variable: you can refer to T in multiple places — parameters, return type, locals — and the compiler tracks that they are the same type. Use it when the relationship between inputs and outputs must be expressed, e.g. returning the same element type you received. <? extends Number> is an upper-bounded wildcard: an anonymous, unknown type that is Number or some subtype, scoped to one use site. Because the exact type is unknown, such a collection is effectively read-only for its element type: you can read elements as Number, but you cannot add anything except null, since the compiler cannot verify the element fits the unknown subtype. Wildcards make APIs more flexible for callers (a List<Integer> matches List<? extends Number>) without forcing a named parameter. Rule of thumb (PECS): use extends wildcards for producers you only read from; use a named type parameter when you need to relate or return the type.

code

java · 14 lines
java
// Named type parameter: relate input and output
static <T extends Number> T firstOf(java.util.List<T> items) {
    return items.get(0); // returns the exact element type
}

// Upper-bounded wildcard: read-only producer, max caller flexibility
static double sum(java.util.List<? extends Number> items) {
    double total = 0;
    for (Number n : items) total += n.doubleValue(); // read OK
    // items.add(1); // compile error: cannot add to ? extends
    return total;
}

// sum accepts List<Integer>, List<Double>, List<Number>, ...

go deeper

for a junior

Knows a wildcard means an unknown subtype and that named T can be reused; may not yet grasp the read-only restriction.

for a middle

Explains that ? extends is read-only for its element and that List<Integer> is not a List<Number>.

for a senior

Applies PECS confidently, chooses named parameter vs wildcard by signature occurrence count, and explains the add-only-null rule.

for a principal

Designs library APIs with deliberate variance, balancing caller flexibility, evolvability, and signature clarity across the surface.

## Two tools that look similar Both `<T extends Number>` and `<? extends Number>` involve the words `extends` and `Number`, but they play different roles. ### A named bounded type parameter: <T extends Number> A **type parameter** `T` is a *named variable for a type*. Once declared on a method or class, you can use `T` in several positions and the compiler enforces that they all denote the **same** type: ```java static <T extends Number> T firstOf(List<T> items) { return items.get(0); // return type T matches the list's element type } ``` Here the caller gets back exactly the element type they passed: `firstOf(List<Integer>)` returns an `Integer`. The name `T` lets you *relate* inputs and outputs. ### An upper-bounded wildcard: <? extends Number> A **wildcard** `?` is an *anonymous unknown type*. `<? extends Number>` means "some specific but unknown type that is `Number` or a subtype." You cannot name it or reuse it elsewhere in the signature. ```java static double sum(List<? extends Number> items) { double total = 0; for (Number n : items) total += n.doubleValue(); // read as Number: fine // items.add(1); // COMPILE ERROR: unknown element type return total; } ``` ## Why a `? extends` collection is read-only for its element Suppose `items` is actually a `List<Integer>`. Adding a `Double` would corrupt it. Because the compiler only knows the element type is *some* subtype of `Number` but not *which* one, it forbids adding any value except `null` (which is a member of every reference type). You **can** read, because whatever the element is, it is guaranteed to be at least a `Number`. This asymmetry — read yes, write no — is the defining behavior of an upper-bounded wildcard. ## Flexibility for callers Generics are **invariant**: `List<Integer>` is NOT a subtype of `List<Number>`, even though `Integer` is a subtype of `Number`. A wildcard restores some flexibility: `List<? extends Number>` accepts `List<Integer>`, `List<Double>`, `List<Number>`, etc. So wildcards widen the set of arguments an API will accept without committing to a named parameter. ## PECS — the decision rule Joshua Bloch's mnemonic **PECS: Producer Extends, Consumer Super**: - If a parameter is a **producer** (you only *read* values out of it), use `? extends`. - If it is a **consumer** (you only *write* values into it), use `? super`. - If you need to **both** read and write, or to **return** the same type, use a **named type parameter** `<T ...>` instead of a wildcard. ## When to choose each - **Named `<T extends Number>`:** when the type appears more than once and must be the same — e.g. a method that takes a `T` and returns a `T`, or relates two parameters. - **Wildcard `<? extends Number>`:** when a single parameter is a read-only producer and you want maximum caller flexibility without needing to name the element type. A useful guideline: if a type parameter appears only **once** in a method signature and you don't need to refer to it, a wildcard is usually the cleaner choice. ## Summary table | Aspect | `<T extends Number>` | `<? extends Number>` | |---|---|---| | Named / reusable | Yes | No (anonymous) | | Relate inputs/outputs | Yes | No | | Read elements as Number | Yes | Yes | | Add elements | Yes (a T) | No (except null) | | Caller flexibility | Exact type | Any subtype of Number |

  • Why can't you add an Integer to a List<? extends Number>?
    The compiler only knows the element type is some unknown subtype of Number; it can't prove an Integer fits that unknown type, so it forbids adding anything but null.
  • What does PECS stand for and how does it guide the choice?
    Producer Extends, Consumer Super: use ? extends for things you read from, ? super for things you write to, and a named type parameter when you must read and write or return the same type.
  • Is List<Integer> assignable to List<Number>?
    No. Generics are invariant, so List<Integer> is not a subtype of List<Number>; List<? extends Number> is the wildcard that accepts it.

saying these in an interview costs you the question

  • Thinking you can add elements (other than null) to a List<? extends Number>
  • Believing List<Integer> is a subtype of List<Number> (generics are invariant)
  • Using a wildcard when you need to return or relate the same type — use a named T
  • Treating <T extends X> and <? extends X> as interchangeable

context