Generics and Collections
Generics and Collections tests compile-time type safety, wildcard use, and choosing the right collection with correct equality and ordering contracts.
Core rules
- Generic types are invariant:
List<Integer>is not aList<Number>. Wildcards restore flexibility. - PECS: use
? extends Tfor producers (reading),? super Tfor consumers (writing). You cannot add to? extends Texceptnull, and reading from? super TgivesObject. - Type erasure removes generic type information at runtime; therefore no
new T(), nonew T[], noinstanceof List<String>, and no static field of a class type variable. Listpreserves insertion order and allows duplicates;Setrejects duplicates byequals/hashCode;Mapkeys are unique;Queue/Dequedefine FIFO/LIFO operations.HashSet/HashMaprely on consistentequals/hashCode;TreeSet/TreeMaprely oncompareTo/Comparatorreturning 0 for equality.Comparabledefines natural ordering;Comparatorsupplies external ordering and supports chaining withthenComparing.
Worked example
void add(List<? super Integer> dst) { dst.add(1); }
void sum(List<? extends Number> src) { for (Number n : src) { } }
add(new ArrayList<Number>()) is legal; sum(new ArrayList<Integer>()) is legal. Inside add, dst.get(0) returns Object, not Integer.
Traps
- Adding to a
List<? extends Number>is illegal. - Generic arrays and
instanceofwith parameterized types are illegal. - Mutating a key after inserting it into a
HashMapcan make it unreachable. TreeSetuses comparison, notequals, so inconsistent comparison breaks uniqueness.List.remove(int)removes by index;remove(Object)removes by value.