Card 03/ 09
Type Erasure: What Is Left of List<String> at Run Time
A list of strings and a list of integers turn out to be exactly the same class.
Type erasure means the compiler checks type arguments and then removes them: at run time a List<String> is just a List, holding Object references. It explains nearly every surprising rule about generics.
Two variables, declared with different type arguments, and a comparison of their classes:
List<String> a = new ArrayList<>();
List<Integer> b = new ArrayList<>();
System.out.println(a.getClass() == b.getClass());trueThey are the same class. The bytecode contains one ArrayList, holding Object references, exactly as it did before generics existed.
| Written | At compile time | At runtime |
|---|---|---|
List<String> | A list that only accepts strings | A list |
refs.get(0) | Produces a String | Produces an Object, cast to String |
T in a generic class | A real type | Object |
The cast in the middle row is the one the compiler writes for you. It is always safe, because the compiler already refused every line that could have put something else into the list.
Erasure was chosen so that code written before Java 5 kept running unchanged on the same virtual machine. It worked, and the price is paid by every strange generics rule you will meet.
So when the compiler refuses something about generics that looks perfectly reasonable, the reason is nearly always that the information you are relying on is gone by the time it would be needed.
← → move through sections and cards