← All articles
Backend1 min read

Java Generics: A Deep Dive

Wildcards, bounds, and type erasure trip up even experienced developers. Understanding the rules makes your APIs both safe and flexible.

S

Swapnika Voora

Author

Generics give you compile-time type safety without casting. The tricky parts — wildcards and erasure — become clear once you learn the guiding principle: PECS.

Producer extends, consumer super

If a structure produces values you read, use extends. If it consumes values you write, use super. This is the PECS rule.

Copy.java
static <T> void copy(List<? extends T> src, List<? super T> dest) {
    for (T item : src) {
        dest.add(item);
    }
}

Bounded type parameters

Constrain a type parameter so you can call methods on it safely.

Max.java
static <T extends Comparable<T>> T max(List<T> items) {
    return items.stream().max(Comparator.naturalOrder()).orElseThrow();
}

Takeaways

  • Type information is erased at runtime — you cannot do new T() or instanceof T.
  • Use bounded wildcards to make APIs accept a wider range of arguments.
  • Prefer generic methods over raw types to keep casts out of your code.

Because of erasure, you cannot create an array of a generic type directly; create Object[] and cast, or use a List instead.

#java#generics#types

More in Backend