Unravel โบ Java concepts โบ Generics and functional
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
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".
- 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? 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<T extends Comparable<T>> T max(List<T> list) says "any T that can compare itself", so the method may call compareTo
- 4List<?> is "a list of anything": good for methods that only need size() or iteration
- Use a wildcard on parameters (Collection<?
- Because of type erasure, generic types do not exist at run time: you cannot do new T(), T[] or instanceof List<String>
- After type checking the compiler erases type parameters to their bound (Object or the first bound) and inserts casts where values are read
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:
- Language constructs:
wildcardbounded-type
Part of a learning path
- Modern Java syntax ยท previous: Pattern matching with instanceof ยท next: Comparable and Comparator
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.