ConceptDifficulty: Intermediate1 min

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:

java
List<String> a = new ArrayList<>();
List<Integer> b = new ArrayList<>();

System.out.println(a.getClass() == b.getClass());
text
true

They are the same class. The bytecode contains one ArrayList, holding Object references, exactly as it did before generics existed.

What the compiler does and what the runtime sees
WrittenAt compile timeAt runtime
List<String>A list that only accepts stringsA list
refs.get(0)Produces a StringProduces an Object, cast to String
T in a generic classA real typeObject

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.