Wildcards and Type Tokens
Source: Effective Java, 3rd Edition — Chapter 5 by Joshua Bloch (Items 30–33)
This lesson finishes Chapter 5: generic methods, bounded wildcards (PECS), varargs with generics, and typesafe heterogeneous containers keyed by Class tokens.
Item 30: Favor generic methods
Methods can be generic too. Type parameters go between modifiers and the return type:
public static <E> Set<E> union(Set<E> s1, Set<E> s2) { ... }
Raw Set union(Set s1, Set s2) compiles with unchecked warnings and erases safety. A parameterized version compiles cleanly and needs no client casts.
Generic singleton factory: one stateless object serves all type parameterizations because of erasure — e.g. Function.identity(). A private UnaryOperator<Object> plus a generic factory method with narrow @SuppressWarnings("unchecked") is the pattern.
Recursive type bound: mutual comparability — elements comparable to each other:
public static <E extends Comparable<E>> E max(Collection<E> c)
Read <E extends Comparable<E>> as “E that can be compared to itself.”
Item 31: Use bounded wildcards to increase API flexibility
Generics are invariant: Stack<Number> cannot accept Iterable<Integer> even though Integer extends Number.
PECS — producer-extends, consumer-super:
| Role | Wildcard | Example |
|---|---|---|
Producer (source of T) | <? extends T> | pushAll(Iterable<? extends E> src) |
Consumer (sink for T) | <? super T> | popAll(Collection<? super E> dst) |
| Both producer and consumer | exact type | no wildcard |
Do not use wildcards on return types — that forces clients to use wildcards too.
Flexible union:
public static <E> Set<E> union(Set<? extends E> s1, Set<? extends E> s2)
Revised max:
public static <T extends Comparable<? super T>> T max(List<? extends T> list)
Comparable and Comparator are consumers — prefer Comparable<? super T>.
Wildcard capture: public swap(List<?> list, int i, int j) delegates to private <E> void swapHelper(List<E> list, ...).
If a type parameter appears once in a public method, prefer a wildcard (List<?> over <E> List<E>) unless you need capture.
PECS and wildcards
1 / 2Stack<Number>.pushAll(Iterable<Integer> ints)
Pick an answer to see if you are right.
Item 32: Combine generics and varargs judiciously
Varargs builds an array at each call — a leaky abstraction. Generic varargs parameters are non-reifiable, so the compiler warns about heap pollution:
static void dangerous(List<String>... stringLists) { ... } // warning
Storing into the varargs array or returning it (T[] toArray(T... args) { return args; }) breaks type safety — pickTwo returning Object[] assigned to String[] fails at runtime with a hidden cast.
Safe varargs when the array is only a pass-through (read elements, don’t store alien types, don’t escape the array). Annotate with @SafeVarargs on static, final, or (Java 9+) private methods — never on overridable methods unless every override is safe.
Library examples: Arrays.asList, Collections.addAll, EnumSet.of, List.of.
Alternative: take List<T> instead of T... — verbose but provably safe (flatten(List<List<? extends T>> lists)).
Generics and varargs
1 / 2static <T> T[] toArray(T... args) { return args; }
Pick an answer to see if you are right.
Item 33: Consider typesafe heterogeneous containers
Set<E> and Map<K,V> fix one or two type parameters per container. Sometimes you need many types in one bag — parameterize the key, not the whole container.
Type token: Class<T> — String.class has type Class<String>. Favorites API:
public <T> void putFavorite(Class<T> type, T instance);
public <T> T getFavorite(Class<T> type);
Backing store: Map<Class<?>, Object>. Values are stored as Object; type.cast(obj) on read restores the link — no unchecked cast to T.
Runtime safety on put: favorites.put(type, type.cast(instance)). Cannot store favorites keyed by non-reifiable types like List<String>.class (illegal).
Bounded type tokens: Class<T extends Annotation> for getAnnotation. Class.asSubclass(Annotation.class) safely narrows an unbounded Class<?>.
Items 30–33 map
| Item | Move |
|---|---|
| 30 | Generic methods; recursive Comparable<E> bounds |
| 31 | PECS: ? extends producers, ? super consumers |
| 32 | Varargs = arrays; @SafeVarargs only when transmit-only; prefer List |
| 33 | Heterogeneous container: Class<T> keys + type.cast |
Chapter 5 complete. Next: Enums (Chapter 6, Items 34–37).