java泛型类型擦除是设计前提而非障碍,需接受运行时无泛型信息的事实;编译器按边界规则自动擦除,泛型方法需class参数补位,重载、数组和异常类须规避擦除陷阱,反射获取泛型信息可用typetoken技巧。

Java 中泛型类型擦除不是障碍,而是编写通用代码的前提条件——关键在于接受“运行时无泛型信息”这一事实,并围绕它设计方法和类。
泛型类的编写:按边界规则擦除,靠编译器补转换
定义泛型类时,不用手动处理擦除,编译器会自动按规则转换。你只需关注约束是否合理:
- 无上界(
):字段、参数、返回值统一视为 Object,编译器在 get 处插入 checkcast指令保证安全; - 单上界(
):所有 T 的位置被擦成 Number,避免向下转型风险; - 多上界(
):只保留第一个接口 Comparable 作为擦除目标,Cloneable 仅参与编译期校验。
示例:一个安全的数值容器
public class NumberBox<t extends number> {
private T value;
public void set(T value) { this.value = value; }
public T get() { return value; } // 返回值擦为 Number,但调用方仍能接收 Integer/Double
}</t>
使用时无需强转,也不会因擦除而丢失语义:IntegerBox 和 DoubleBox 共享同一份字节码,但类型约束由编译器全程把关。
泛型方法的编写:不依赖运行时类型,用 Class 补位
泛型方法无法在运行时 new T() 或 instanceof T[],所以需显式传入类型凭证:
- 需要创建实例时,加一个 Class
type 参数,再用type.getDeclaredConstructor().newInstance(); - 需要做类型判断时,用
obj.getClass() == type替代obj instanceof T; - 需要数组时,写成
(T[]) new Object[size]并抑制 unchecked 警告,或直接用 ArrayList。
示例:通用 JSON 反序列化方法
public static <t> T fromJson(String json, Class<t> clazz) throws JsonProcessingException {
return new ObjectMapper().readValue(json, clazz);
}</t></t>
调用:fromJson("{\"name\":\"Alice\"}", User.class) —— 类型信息通过 Class 对象带入运行时,绕过擦除限制。
规避常见陷阱:重载、数组与异常类
擦除会导致签名冲突或语法非法,必须提前规避:
- 不要写两个仅泛型不同的重载方法,如
void handle(List<string>)</string>和void handle(List<integer>)</integer>,编译失败; - 避免
T[] arr = new T[10],改用List<t></t>或Object[] + 显式转型; - 泛型类不能继承 Exception,因为 JVM 异常处理机制依赖运行时可识别的类名,擦除后无法区分
MyError<string></string>和MyError<integer></integer>。
需要运行时泛型信息?用 TypeToken 技巧
当反射获取父类泛型(如继承自 ArrayList<user></user>)时,可用匿名子类保留签名:
Type type = new TypeToken<list>>() {}.getType();
// 再通过 ParameterizedType 提取实际类型参数
</list>
这是 Gson、Jackson 等库解析嵌套泛型的核心手法,本质是利用类加载时保留的 Signature 属性,而非依赖对象实例。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











