What is type erasure in Java, and what does it mean for your code at run time?
Type erasure is how the Java compiler implements generics. When it compiles a generic class or method, it erases the type parameters: it removes them from the class file and replaces every use of them with the appropriate type or bound.
For an unbounded type parameter the replacement is Object. For a bounded one, it is the bound — so T extends Number becomes Number. The compiler then inserts casts wherever the compiler needs them, which is why you never see a cast in the source but the program still works at run time.
import java.util.ArrayList;
import java.util.List;
public class Main {
public static void main(String[] args) {
List<String> strings = new ArrayList<>();
List<Integer> numbers = new ArrayList<>();
strings.add("hello");
// At run time both are just a List.
System.out.println("same class : " + (strings.getClass() == numbers.getClass()));
System.out.println("class name : " + strings.getClass().getName());
// The compiler inserted the cast for you.
String first = strings.get(0);
System.out.println("element : " + first.getClass().getSimpleName());
// You cannot ask a generic object what its type parameter was.
System.out.println("no type argument survives at run time");
}
}The output shows the erasure in action. The two lists have the same runtime class, because List<String> and List<Integer> are the same type at run time. And the element still prints as a String, because the compiler inserted the cast.
Type erasure exists for compatibility. When generics were added, the enormous body of earlier code had to keep working, including code that called into libraries. Erasure means a generic class has the same class file shape as it would without generics, so old binaries and new ones interoperate. It also means the raw types you see in older code are not a separate thing — they are the erased type.
The consequences are real. You cannot overload two methods that differ only by type argument. You cannot use a primitive as a type argument without boxing. You cannot check a type parameter with instanceof. And you cannot recover the type argument from a generic object at run time, which is why frameworks that need it use reflection or explicit type tokens.