OOP

24. Generics and Type Erasure

Generics provide compile-time type safety; type erasure removes generic type information at runtime. A List<String> is just a List in bytecode โ€” causing instanceof limits and unchecked cast warnings.

Java 21 (core language)

Explanation

Generics are a compile-time feature. The compiler inserts type checks and casts where needed, then erases the type parameters โ€” the bytecode for List<String> and List<Integer> is identical: plain List. This design kept generics backwards-compatible with pre-Java-5 code.

Consequences of type erasure: you cannot use instanceof with parameterised types (obj instanceof List<String> is a compile error; only obj instanceof List<?> is allowed). You cannot create generic arrays (new T[] fails). Static fields/methods cannot reference class type parameters.

Raw types (List without <>) bypass all generic checking and exist only for backwards compatibility โ€” never use them in new code. The diamond operator (<>) (Java 7+) lets the compiler infer type arguments: new ArrayList<>().

Example

import java.util.ArrayList;
import java.util.List;

public class GenericsTypeErasure {
    // Generic method
    static <T extends Comparable<T>> T max(T a, T b) {
        return a.compareTo(b) >= 0 ? a : b;
    }

    // Generic class
    static class Box<T> {
        private T value;
        Box(T value) { this.value = value; }
        T get() { return value; }
        @Override public String toString() { return "Box[" + value + "]"; }
    }

    public static void main(String[] args) {
        // Compile-time type safety
        List<String> strings = new ArrayList<>();
        strings.add("Hello");
        // strings.add(42); // compile error โ€” caught at compile time

        // Type erasure at runtime: List<String> is just List in bytecode
        Object obj = strings;
        // obj instanceof List<String> โ€” compile error!
        System.out.println(obj instanceof List<?>); // true (wildcard OK)

        // Unchecked cast warning (dangerous, but compiles)
        @SuppressWarnings("unchecked")
        List<Integer> ints = (List<Integer>) obj; // erased to same List type
        // ints.get(0) would throw ClassCastException at runtime (hidden cast)

        // Diamond operator
        Box<String> box = new Box<>("Java 21");
        System.out.println(box);

        // Generic method
        System.out.println(max("apple", "banana")); // "banana"
        System.out.println(max(3, 7));               // 7

        // Raw type (avoid!)
        @SuppressWarnings("rawtypes")
        List raw = new ArrayList();
        raw.add("anything"); // no warning โ€” unsafe
    }
}

Sources