๐ŸŽ“ A1Learner
๐Ÿ”
0 of 40 lessons completed

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?