Java Type Erasure
Type erasure means the compiler removes the type arguments when it builds the program. At runtime, a List<String> and a List<Integer> are the same class.
One class at runtime
Two lists hold different element types. Their getClass answers compare equal.
import java.util.ArrayList;
import java.util.List;
public class Main {
public static void main(String[] args) {
List<String> names = new ArrayList<>();
List<Integer> scores = new ArrayList<>();
System.out.println(names.getClass() == scores.getClass());
System.out.println(names.getClass().getSimpleName());
}
}instanceof cannot check the element type
The holder is typed as Object, so the test would have to trust the String part of the type. The compiler refuses, because erasure leaves nothing to check at runtime.
import java.util.ArrayList;
import java.util.List;
public class Main {
public static void main(String[] args) {
Object holder = new ArrayList<String>();
System.out.println(holder instanceof List<String>);
}
}Overloads that erase to one method
The two show methods differ only in the element type inside List. After erasure both are show(List), so the compiler refuses the pair.
import java.util.ArrayList;
import java.util.List;
public class Main {
static void show(List<String> values) {
System.out.println(values.size());
}
static void show(List<Integer> values) {
System.out.println(values.size());
}
public static void main(String[] args) {
ArrayList<String> names = new ArrayList<>();
names.add("Ana");
show(names);
}
}Example
import java.util.ArrayList;
import java.util.List;
public class Main {
public static void main(String[] args) {
List<String> names = new ArrayList<>();
names.add("Ana");
List<Integer> scores = new ArrayList<>();
scores.add(90);
System.out.println(names.getClass() == scores.getClass());
System.out.println(names instanceof List<?>);
System.out.println(names.size() + scores.size());
}
}Key points
- Generics are checked at compile time, and the type arguments are erased before runtime.
- getClass answers the same ArrayList class for lists of any element type.
- instanceof cannot test an element type, because that information is gone at runtime.
- Two methods that differ only in a list element type clash, because both erase to the same signature.
- A wildcard check like instanceof List<?> still works, because it claims nothing about the element type.
In this example, the two lists report the same class because their type arguments were erased. The wildcard instanceof test still passes, because it only claims the value is a list.
Note
Erasure is why generic code and older raw-type code can mix in one program.
Try it Yourself
Edit the code, then press Run.
Running is simulated
Exercise
Why do List<String> and List<Integer> report the same getClass() result?