java泛型在运行时被擦除,list和list编译后均为原始类型list,反射调用add(object)等方法可绕过编译检查插入任意object子类,但取值时强转失败才抛classcastexception,属反模式。

Java 泛型本身没有运行时类型约束,“强制擦除红线”不是真的突破限制,而是利用编译后已擦除的现实,跳过编译检查、直接调用原始方法。它不新增能力,只是暴露了泛型本就“不存在于运行时”的本质。
理解擦除是前提:JVM 根本不认泛型
泛型是编译期特性。List
反射调用原始 add/remove 方法
目标不是“改泛型”,而是绕过编译器,直连 JVM 认可的方法签名:
- 用 list.getClass().getMethod("add", Object.class) 获取原始 add 方法(注意别用 getDeclaredMethod,避免访问权限问题)
- 调用 invoke(list, new Date()) 或 invoke(list, 42) —— 参数只要是 Object 子类,就完全合法
- 同理,remove、set 等方法也可用 Object.class 参数反射获取并调用
风险只在取值时爆发,而非插入时
插入成功不等于安全。错误被延迟到你真正使用元素的时候:
- for (String s : list) 遇到 Integer 就抛 ClassCastException
- String s = list.get(1) 同样失败,因为 get() 返回 Object,强转失败
- Stream 操作如 map(String::length) 在执行 lambda 时崩,堆栈难定位
- IDE 和 javac 完全静默,无任何提示
想“安全地”动态处理类型,别依赖擦除漏洞
靠反射硬塞异构对象是反模式。更可控的做法是:
- 用 List 显式声明,配合文档和单元测试说明约定
- 封装带校验的容器:TypedBox
构造时传入 Class ,add 前用 isInstance 检查 - 序列化/反序列化时传 TypeReference
- > {}
- 框架层(如 MyBatis)通过父类继承关系(getGenericSuperclass())提取实参,而非猜测实例类型











