20 · 32 · 5 min
Types as parameters
Before generics, a collection held Object and every read needed a cast that could fail at run time.
List names = new ArrayList();
names.add("Priya");
names.add(42); // compiles
String s = (String) names.get(1); // ClassCastException, at run timeGenerics move that failure to compile time.
List<String> names = new ArrayList<>();
names.add(42); // will not compileWriting one
public class Box<T> {
private final T value;
public Box(T value) { this.value = value; }
public T get() { return value; }
}
Box<String> b = new Box<>("hello");
String s = b.get(); // no castThe class is written once and is type safe for every use.
Bounded types
Sometimes the parameter must support something:
public static <T extends Comparable<T>> T max(List<T> items) {
T best = items.get(0);
for (T item : items)
if (item.compareTo(best) > 0) best = item;
return best;
}Without the bound, compareTo is not available, because T could be anything.
Why a List of Dog is not a List of Animal
List<Dog> dogs = new ArrayList<>();
List<Animal> animals = dogs; // does not compile, and correctly
animals.add(new Cat()); // would have put a Cat in a List<Dog>Generics are invariant for exactly this reason. Arrays in Java are covariant, which is why the equivalent compiles and then throws ArrayStoreException at run time, a known design mistake.
Wildcards recover the flexibility safely:
void printAll(List<? extends Animal> animals) // can read Animals, cannot add
void addDogs(List<? super Dog> target) // can add Dogs, reads as ObjectThe mnemonic is producer extends, consumer super: use extends when the collection produces values for you, super when you put values into it.
What happens at run time
Java uses erasure: the types are checked at compile time and removed, so List<String> and List<Integer> are the same class at run time. That is why you cannot write new T[] or ask x instanceof List<String>.
C# keeps the types at run time, so both are possible there. C++ templates generate a separate specialised copy per type, which is faster and produces famously long error messages.