What is type erasure, and what limitations does it impose?
Quick Answer
Type erasure means the compiler enforces generic type constraints at compile time, then replaces type parameters with their bounds (or Object) in the compiled bytecode, so no generic type information exists at runtime. This means you can't do new T(), can't use instanceof with a parameterized type, can't create a generic array directly, and all instances of a generic class share one .class file regardless of their type argument.
Detailed Answer
Java generics are a compile-time only feature — the JVM itself has no concept of List<String> vs List<Integer>; both compile down to plain List (using Object, or the bound type, internally). This is type erasure: the compiler checks your generic type usage for correctness, inserts the necessary casts, and then discards the type parameter information.
Consequences / limitations:
- Can't create an instance of a type parameter:
new T()doesn't compile — the compiler has no idea whatTactually is at runtime. - Can't check generic types with
instanceof:if (obj instanceof List<String>)doesn't compile — onlyobj instanceof List(the raw type) is allowed, since the<String>information is erased. - Can't create a generic array directly:
new T[10]ornew List<String>[10]doesn't compile, due to interactions with array covariance and erasure that could otherwise let you store the wrong type undetected. - All parameterized instances share one class:
List<String>.classandList<Integer>.classare the sameClassobject at runtime —list1.getClass() == list2.getClass()istrueeven for different element types. - Overloading on erased types conflicts: you can't overload
void foo(List<String> s)andvoid foo(List<Integer> i)in the same class — after erasure, both becomevoid foo(List).
Erasure exists mainly for backward compatibility: it let pre-generics bytecode (Java 1.4 and earlier) keep working alongside generic code without a parallel, incompatible runtime type system.