Type Erasure là quá trình compiler Java xóa thông tin kiểu generic (type parameters) tại compile-time, thay thế bằng Object hoặc bound type. Bytecode runtime không chứa generic type info.
Tại sao cần Type Erasure?
- Backward compatibility: Java 5 generics phải chạy trên JVM pre-generics (Java 1.4) không sửa đổi bytecode format.
- Migration compatibility: Code non-generic cũ tương tác seamless với code generic mới.
Quy trình Type Erasure (3 bước)
- Replace type parameters: Unbounded
<T>→Object. Bounded<T extends Number>→Number(leftmost bound). - Insert synthetic casts: Thêm ép kiểu (checkcast) tại các chỗ cần type safety (get, assignment).
- Generate bridge methods: Khi override method generic trong subclass/interface, compiler tạo bridge method để bảo toàn polymorphism.
Ví dụ minh họa
// Source code Listlist = new ArrayList<>(); list.add("Hello"); String s = list.get(0); // Không cần cast // Sau Type Erasure (bytecode tương đương) List list = new ArrayList(); // Raw type list.add("Hello"); // Unchecked warning tại compile String s = (String) list.get(0); // Synthetic cast: checkcast java/lang/String
Ví dụ Bridge Method
// Source interface Comparable{ int compareTo(T o); } class MyClass implements Comparable { public int compareTo(MyClass other) { return 0; } } // Bytecode: Compiler sinh thêm bridge method // public int compareTo(Object o) { return compareTo((MyClass)o); } // Bridge // public int compareTo(MyClass other) { return 0; } // Actual
Hệ quả quan trọng (Gotchas)
| Hệ quả | Mô tả | Ví dụ |
|---|---|---|
Không thể new T() | T bị erasure thành Object → không biết constructor. | Dùng Supplier hoặc reflection. |
Không thể T[] array | Array cần component type runtime. Generic array creation không allowed. | Dùng List hoặc (T[]) new Object[n] (unchecked). |
Không thể instanceof T | T erased → instanceof raw type. | Dùng Class token + clazz.isInstance(obj). |
| Không thể overload bằng generic | Erasure trùng nhau. | void m(List và void m(List → conflict. |
| Static field/method không dùng type parameter | Static thuộc class raw, không phải instance. | static T field; lỗi compile. |
| Exception generic không được catch | Catch clause cần runtime type. | catch (T e) lỗi. Dùng catch (Exception e) + check. |
| Heap pollution | Raw type gán vào generic var → runtime ClassCastException ở chỗ khác. | Dùng @SafeVarargs, tránh raw type, varargs generic cẩn thận. |