Java 14: Type Erasure & Bridge Methods
easy⏱ 5 mincoursejava
What gets erased
After compilation, List<String> becomes List, Box<T> becomes Box with T replaced by its bound (default Object). Casts are inserted at call sites. This means: (1) list.getClass() == list2.getClass() for any two generic lists, (2) you can't overload on different type parameters alone — method(List<String>) and method(List<Integer>) collide.
List<String> a = new ArrayList<>();
List<Integer> b = new ArrayList<>();
System.out.println(a.getClass() == b.getClass()); // true — both ArrayList
What you can't do
You can't: (1) create a generic array new T[n] (compiler needs reified T), (2) throw a generic exception throw new MyException<String>(...) (catch uses instanceof), (3) write instanceof List<String> (use instanceof List<?>), (4) have two methods void f(List<A>) and void f(List<B>) — both erase to f(List).
Bridge methods
When a generic class is overridden, the compiler generates a bridge method — a synthetic method with erased types that delegates to the real overriding method. This keeps the vtable consistent across erasure. You'll see it in stack traces as a method with $bridge or in getDeclaredMethods.
class Parent<T> { T value; T get() { return value; } }
class StringChild extends Parent<String> {
@Override String get() { return value; } // override
}
// Compiler adds synthetic:
// Object get() { return (String) this.getAsString(); } // bridge
Prove erasure at runtime
Create two GenericBox<T> instances — one with a string, one with a number. Log their 'class name' (use a marker field that mirrors what getClass() would return). They should be identical — GenericBox, not GenericBox<string>. Then show an overloaded method conflict.
TypeToken & super type tokens
To carry generic info at runtime (e.g. for JSON deserialization), libraries like Guava and Jackson use super type tokens: new TypeToken<List<String>>(){}. The anonymous subclass preserves the parameterized type in its reflective signature, which the library reads via reflection.
Quiz: Array vs List
Why can you do new String[10] but not new T[10]? Arrays are reified — they carry their component type at runtime. Generics are erased. That's also why arrays are covariant but generics are invariant.