Generics in depth
Type parameters, bounded types and wildcards let one piece of code work safely with many types.
- Write a type parameter once instead of a class per type.
- Bound a type parameter with extends to unlock its methods.
- Use ? extends for reading and ? super for writing.
- Remember type erasure when you need type info at runtime.
In plain English
Generics let one class or method work safely with many types instead of repeating code for each one. A type parameter is a placeholder such as T or E that gets replaced by a real type when you use the generic. A bounded type parameter, such as T extends Number, restricts what the placeholder may be so you can call methods on it. A wildcard is a question mark used when a type is unknown, where ? extends X means some subtype of X and ? super X means some supertype of X. Type erasure is the fact that the compiler removes generic type information after checking it, so at runtime a List<String> and a List<Integer> are the same class.
Step by step
- 1Declare a class with a type parameter in angle brackets.
- 2Use the type parameter for fields, a constructor and a method.
- 3Bound the parameter with extends to call its methods.
- 4Use ? extends to read from a generic list.
- 5Write a generic method with its own type parameter.
import java.util.List;
class Box<T> {
private final T value;
Box(T value) {
this.value = value;
}
public T value() {
return value;
}
}
class Numbers {
public static double sum(List<? extends Number> values) {
double total = 0;
for (Number value : values) {
total += value.doubleValue();
}
return total;
}
public static <T extends Comparable<T>> T max(List<T> values) {
T best = values.get(0);
for (T value : values) {
if (value.compareTo(best) > 0) {
best = value;
}
}
return best;
}
}Common mistakes
- Using a raw type such as List instead of List
<String>turns off the compiler safety generics exist to give you. - Trying to add a value to a List
<? extends Number>fails to compile, because the exact element type is unknown. - Expecting to see the type parameter at runtime is wrong, because type erasure removes generic type information after compilation.
- Creating an array of a generic type such as new T[10] fails to compile, since erasure prevents the runtime from knowing the real type.
Write a bounded max method
Write a generic static method largest that takes a List<T> and returns the largest element, where T is bounded to Comparable<T>.
public static <T> T largest(List<T> values) {
return values.get(0);
}What does type erasure mean for a List<String> and a List<Integer> at runtime?
Make it yours.
Keep a private note for this lesson, then turn the key ideas into flashcards you can revisit.
Lock in what you just learned.
Mark this lesson complete to save your place and move one step closer to the certificate.