Java泛型的安全性完全依赖编译期检查与自动转换:编译器在擦除前校验add等操作,擦除后自动插入转型,禁止new T等破坏性语法,并通过桥接方法保障多态正确性。

Java 泛型在集合中不靠运行时“保证安全”,而是把类型安全的重担完全交给编译期——类型擦除本身并不提供运行时保护,它恰恰是为兼容性让渡了运行时类型信息;真正的安全来自编译器在擦除前完成的严格检查和自动插入的转换逻辑。
编译期强校验:提前拦截非法操作
当你声明 List<string></string> 并调用 add() 时,编译器会立刻验证实参是否可赋值给 String。比如:
-
list.add("ok")✅ 通过 -
list.add(123)❌ 编译失败,报错 “incompatible types” -
list.add(null)✅ 允许(因为null可赋值给任意引用类型)
这种检查发生在擦除之前,是类型安全的第一道防线。
擦除后自动补转换:隐藏强制转型
擦除不是简单删除泛型标记,而是有策略地生成等效原始代码,并在取值位置插入隐式转型:
立即学习“Java免费学习笔记(深入)”;
- 源码:
String s = list.get(0); - 擦除后等效字节码行为:
String s = (String) list.get(0);
这个转型由编译器自动生成并保证正确——前提是前面的 add() 操作已通过校验。若有人绕过泛型(如用原生 List 添加非 String),该转型会在运行时抛 ClassCastException,但那属于违规使用,不是泛型机制失效。
禁止破坏性操作:从语法上堵死漏洞
类型擦除直接导致某些操作在语言层面被禁止,从而避免逻辑矛盾:
- 不能写
new T()—— 因为运行时没有T的类信息 - 不能写
if (obj instanceof T)——T在运行时不存在 - 不能声明
static T field—— 静态变量属于类而非实例,而擦除后所有泛型实例共享同一份字节码 - 不能重载
void m(List<string>)</string>和void m(List<integer>)</integer>—— 擦除后签名相同,编译报错
桥接方法:维护多态语义不塌方
当泛型类继承或实现参数化接口时(如 class MyList<e> implements List<e></e></e>),擦除会导致子类方法签名与父类/接口不匹配。编译器自动插入桥接方法来转发调用:
- 你写的
public E get(int i)→ 擦除为public Object get(int i) - 编译器额外生成一个
public Object get(int i)桥接方法,内部调用你的E get()
这样,外部通过原始类型引用调用时仍能走对逻辑,多态行为不因擦除而错乱。


















