Why it matters

Generics are what let ArrayList<String> catch type errors at compile time. Without them, casts everywhere would fail at runtime. This is worth learning.

Advertisement

The architecture

Type parameters: 'class Box<T> { T value; }'. Instantiated with concrete types: Box<String>. The compiler checks that operations on T are valid for the actual type.

Bounded types: 'class NumberBox<T extends Number>'. Restricts T to Number or subclasses.

Generics syntaxType parameterT, E, K, VBoundedextends / superWildcards? extends, ? superRuntime erases T to bound (default Object); casts inserted at use sites
Generics elements.
Advertisement

How it works end to end

Wildcards: '? extends T' (upper bounded, covariant) accepts T or any subtype. '? super T' (lower bounded, contravariant) accepts T or any supertype. Bare '?' accepts anything.

PECS mnemonic: Producer Extends, Consumer Super. If you produce T (read from), use ? extends T. If you consume T (write to), use ? super T.

Type erasure: at runtime, generic types are erased to their bound (Object by default). List<String> and List<Integer> are the same at runtime. This means no runtime type introspection on generic parameters.