BackendBench
Coffee

Unravel โ€บ Java concepts โ€บ Generics and functional

Java language

Wildcards and bounded generics

List<? extends Number> means "a list of some kind of Number, I do not know which"; List<? super Integer> means "a list that accepts Integers". Bounds like <T extends Comparable<T>> limit what a type parameter may be.

Learn these first

At a glance

Mental model

A ? extends box is a read-only display case of "some fruit": you can take a fruit out, but you cannot put one in because you do not know which fruit it holds. A ? super box is an "apples welcome" donation bin: you can drop apples in, but what comes out is just "some thing".

What happens, in order
  1. 1A List<Integer> is not a List<Number>, even though Integer is a Number: if it were, you could add a Double to a list of IntegersWildcards express the flexible version.
  2. 2? extends T (upper bound): produce values of type T? super T (lower bound): consume values of type T. This is the PECS rule: Producer Extends, Consumer Super.
  3. 3<T extends Comparable<T>> T max(List<T> list) says "any T that can compare itself", so the method may call compareTo
  4. 4List<?> is "a list of anything": good for methods that only need size() or iteration
Remember
Watch out
Trying to add elements to a List<?Using wildcards in return typesExpecting generic type information at runtime
Example (highlighted lines explain it)
import java.util.*;public class Stats {  static double sum(Collection<? extends Number> numbers) {    double total = 0;    for (Number n : numbers) total += n.doubleValue();    return total;  }  static void fill(List<? super Integer> out) { out.add(1); out.add(2); }  static <T extends Comparable<T>> T max(List<T> list) { return Collections.max(list); }}
Read the full explanation (about 2 min)

List<? extends Number> means "a list of some kind of Number, I do not know which"; List<? super Integer> means "a list that accepts Integers". Bounds like <T extends Comparable<T>> limit what a type parameter may be.

A mental model

A ? extends box is a read-only display case of "some fruit": you can take a fruit out, but you cannot put one in because you do not know which fruit it holds. A ? super box is an "apples welcome" donation bin: you can drop apples in, but what comes out is just "some thing".

How it works

A List<Integer> is not a List<Number>, even though Integer is a Number: if it were, you could add a Double to a list of Integers. Wildcards express the flexible version.

? extends T (upper bound): produce values of type T. ? super T (lower bound): consume values of type T. This is the PECS rule: Producer Extends, Consumer Super.

<T extends Comparable<T>> T max(List<T> list) says "any T that can compare itself", so the method may call compareTo.

List<?> is "a list of anything": good for methods that only need size() or iteration.

Going deeper

Use a wildcard on parameters (Collection<? extends Item>) to make an API accept more, and a concrete type on return values so callers do not have to deal with wildcards.

Because of type erasure, generic types do not exist at run time: you cannot do new T(), T[] or instanceof List<String>. The bound is what the compiler uses to check calls.

Under the hood

After type checking the compiler erases type parameters to their bound (Object or the first bound) and inserts casts where values are read. That is why List<String> and List<Integer> are the same class at run time.

Common mistakes

  • Trying to add elements to a List<? extends X>.
  • Using wildcards in return types.
  • Expecting generic type information at runtime.

How Unravel recognises it

When you paste code, Unravel looks for these signs of wildcards and bounded generics. Spotting them yourself is a good habit when you read unfamiliar code:

Part of a learning path

Related concepts

Frequently asked questions

What is Wildcards and bounded generics?

List<? extends Number> means "a list of some kind of Number, I do not know which"; List<? super Integer> means "a list that accepts Integers". Bounds like <T extends Comparable<T>> limit what a type parameter may be.

What are the most common mistakes with Wildcards and bounded generics?

Trying to add elements to a List<? extends X>. Using wildcards in return types. Expecting generic type information at runtime.

How can I see Wildcards and bounded generics in real code?

Paste your own Java into Unravel and it will point out where wildcards and bounded generics appears, explain how it works at the detail level you choose, and draw the flow of the code around it.