Generics
Generics Restrictions
Erasure imposes a fixed list of "cannots": no primitives as type arguments, no
new T(), no generic arrays, no generic exceptions, no static fields of type T. Each has a standard workaround.- No primitive type arguments —
List<int>is illegal; boxing or specialized streams instead - No
new T()/new T[]— pass aClass<T>token orIntFunction<T[]>likeString[]::new - No generic array creation:
new List<String>[10]is illegal (heap pollution) - Static fields/methods cannot use the class's type parameter
- No
catch (T e), no genericThrowablesubclasses - Overloads that erase to the same signature clash
// Illegal: generic array creation
// Pair<String>[] table = new Pair<String>[10];
// Why: arrays check stores at runtime using the ELEMENT type,
// which erasure has destroyed. This would compile and corrupt silently:
Object[] objs = table; // arrays are covariant
objs[0] = new Pair<Employee>(...); // ArrayStoreException CANNOT fire — erased!
// Workarounds:
List<Pair<String>> table2 = new ArrayList<>(); // best: use a list (EJ 28)
Pair<String>[] table3 = (Pair<String>[]) new Pair<?>[10]; // classic @SuppressWarnings danceVarargs + generics = "heap pollution" warnings, because varargs create an array of the erased type. @SafeVarargs (EJ Item 32) asserts your method only reads the array and never stores into it or leaks it — the JDK's own List.of(...) carries it.
// Illegal: T could be abstract, and erasure loses the constructor anyway
// public Pair() { first = new T(); }
// Standard fixes:
public static <T> Pair<T> makePair(Supplier<T> constr) {
return new Pair<>(constr.get(), constr.get());
}
Pair<String> p = makePair(String::new);
// Or a type token:
public static <T> Pair<T> makePair(Class<T> cl) throws Exception {
return new Pair<>(cl.getConstructor().newInstance(), ...);
}