Generics (Java 5+) cho phép viết class/method với type parameter — type-safe lúc compile mà không cần cast tay.
java
List<String> list = new ArrayList<>();
list.add("hi");
String s = list.get(0); // không cần cast
list.add(123); // compile ERRORType erasure: compiler xoá type parameter sau khi check xong → bytecode chỉ có raw type. List<String> và List<Integer> runtime đều là List. Lý do: backward compat với code Java 1.4. Khác C# (reified generics).
Hậu quả của erasure:
java
if (obj instanceof List<String>) { } // ❌ — chỉ instanceof List<?>
T[] arr = new T[10]; // ❌ không tạo array generic
void f(List<String> l) { }
void f(List<Integer> l) { } // ❌ cùng erasure
static T value; // ❌ không static field genericBounded: <T extends Number> — T phải là Number hoặc subtype.
Wildcards — PECS (Producer Extends, Consumer Super):
java
void copy(List<? extends Number> src) { // ĐỌC OK, ghi KHÔNG
Number n = src.get(0);
}
void add(List<? super Integer> dest) { // GHI OK, đọc trả Object
dest.add(1);
}- Cần đọc →
<? extends T>(producer). - Cần ghi →
<? super T>(consumer). - Cần cả 2 →
<T>exact.
Workaround: truyền Class<T> hoặc TypeReference (Jackson) để giữ type runtime.