Why does Java have generics, and what problems do they solve?
Quick Answer
Generics let classes, interfaces, and methods be parameterized by type, so collections and utility classes can be reused for any type while the compiler enforces type safety at compile time. Before generics, collections stored plain Object references, requiring manual casts that could fail at runtime with a ClassCastException; generics catch those mistakes at compile time instead.
Detailed Answer
Before generics (pre-Java 5), collections held plain Object references:
List list = new ArrayList();
list.add("hello");
list.add(42); // no compile-time complaint — mixed types allowed
String s = (String) list.get(1); // compiles, but throws ClassCastException at runtime
Generics let you parameterize a type with the element type it holds, moving that error from a runtime surprise to a compile-time error:
List<String> list = new ArrayList<>();
list.add("hello");
list.add(42); // compile error — caught immediately
String s = list.get(0); // no cast needed
Benefits:
- Compile-time type checking — catches type mismatches before the program ever runs.
- Eliminates explicit casts — the compiler inserts them safely where needed.
- Enables generic algorithms — a single
sortmethod can work correctly onList<String>,List<Integer>, etc., without duplication.
Generics are implemented via type erasure (the compiler enforces the constraints, then strips the type parameter information for the compiled bytecode) — which explains several of their more advanced quirks and limitations.