Java泛型是编译期特性,运行时类型擦除,但可通过子类显式继承(如Child extends Parent<String>)、TypeReference匿名子类固化、父类提供Type Token三种方式间接获取泛型实参。

Java 中泛型是**编译期特性**,运行时会发生类型擦除,所以子类继承父类时,无法直接在运行时获取父类的泛型实际类型(比如 Parent<String> 擦除后只剩 Parent)。但有几种常用方式可以在子类中“保留”或**间接获取**父类泛型实参,核心思路是利用编译期可推断的类型信息 + 运行时反射辅助。
通过子类显式声明泛型并传递类型参数
让子类自己带上泛型,并在继承时明确指定父类泛型实参,这样编译器能推导出类型,部分场景下可通过反射提取(需配合 Type 层次结构):
- 父类定义为
class Parent<T> { ... } - 子类写成
class Child extends Parent<String> { ... }—— 此时Child的直接父类类型在字节码中记录为Parent<String>,尚未被擦除 - 在
Child中可用getClass().getGenericSuperclass()获取ParameterizedType,再调用getActualTypeArguments()取出String.class
使用 TypeReference 或匿名子类“固化”泛型信息
这是最常用、最可靠的技巧:借助匿名内部类在创建时捕获泛型签名,绕过直接实例化的擦除问题:
- 定义一个空的抽象基类如
abstract class TypeReference<T> {} - 在子类中写:
TypeReference<List<User>> ref = new TypeReference<List<User>>() {}; - 由于匿名子类会保留其父类的泛型实参(
TypeReference<List<User>>),调用ref.getClass().getGenericSuperclass()就能得到完整的带参类型 - 很多 JSON 库(如 Jackson、Gson)的
TypeReference就是基于这个原理
在父类中提供类型令牌(Type Token)字段
如果控制父类设计,可在父类中强制子类传入 Class<T> 或 Type,把类型信息“存下来”:
Java Maven 项目审查工作流的通用输入处理。当 Java Maven 项目以 ZIP压缩包或 GitLab 仓库 URL 形式提供且需要...时使用。
立即学习“Java免费学习笔记(深入)”;
- 父类加构造函数:
protected Parent(Class<T> type) { this.type = type; } - 子类构造时显式传入:
super(String.class); - 后续所有类型相关逻辑(如反序列化、类型检查)都基于该
Class对象,不依赖反射推断 - 缺点是不够自动,需要子类配合;优点是简单、稳定、100% 运行时可用
注意边界:无法恢复已擦除的局部泛型或通配符
以下情况**无法还原**原始泛型实参:
- 父类用
Parent<?>或Parent<? extends Number>继承 —— 通配符信息在字节码中不完整,反射拿不到具体上界 - 泛型参数来自方法签名或局部变量(如
<T> void foo(T t))—— 方法级泛型完全不参与类签名,运行时不可见 - 子类未显式指定父类泛型(如
class Child extends Parent)—— 父类退化为原生类型,无泛型信息可查
不复杂但容易忽略:关键在于“谁在编译时绑定了具体类型”,只有在类继承关系中显式写出泛型实参,且该子类被 JVM 加载时,其 Class 对象才可能携带可反射提取的泛型信息。

















