java泛型在运行时被擦除,但通过反射可获取字段、方法签名及父类继承中保留的泛型信息:用field.getgenerictype()、method.getgenericreturntype()和getgenericsuperclass()配合parameterizedtype提取实参,嵌套泛型可递归解析;局部变量和类型变量等场景无法恢复泛型信息。

Java 泛型在编译后会被擦除(Type Erasure),运行时 Object、List<string></string>、List<integer></integer> 都变成原始类型 List,无法直接通过 getClass() 拿到泛型参数。但**只要泛型信息在字节码中以某种形式保留下来(比如作为字段类型、方法返回值、父类继承关系),就可以通过反射配合 java.lang.reflect 相关 API 提取实际类型**。
利用 Field.getGenericType() 获取成员变量的泛型类型
这是最常见且可靠的方式——当泛型用在类字段上时,JVM 会把完整类型信息写入字节码的 Signature 属性中。
例如:
private List
private Map
}
可通过反射获取:
- 调用
field.getGenericType()得到ParameterizedType实例 - 用
getRawType()拿到原始类型(如List.class) - 用
getActualTypeArguments()获取泛型实参数组(如[String.class]或[Integer.class, List<boolean>.class]</boolean>) - 对嵌套泛型(如
List<boolean></boolean>),可递归判断是否为ParameterizedType并继续展开
通过 Method.getGenericReturnType() 或 getGenericParameterTypes()
方法签名中的泛型也会保留在字节码中。
例如:
public Listpublic void process(Map
反射时:
-
method.getGenericReturnType()返回ParameterizedType,可提取List<user></user>中的User.class -
method.getGenericParameterTypes()返回参数类型的泛型表示,支持多层嵌套解析 - 注意:仅适用于**声明时带泛型的方法**,运行时传入的泛型实例(如
new ArrayList<string>()</string>)无法还原
借助 superclass 和 getGenericSuperclass() 获取父类泛型实参
这是处理泛型基类(如 Dao<user></user>)最常用技巧。
例如:
class UserDao extends Dao在 UserDao 内部可通过:
-
this.getClass().getGenericSuperclass()得到ParameterizedType表示的Dao<user></user> - 再调用
getActualTypeArguments()[0]直接拿到User.class - 若继承链更长(如
A<t> extends B<t></t></t>),需向上遍历getGenericSuperclass()并匹配目标类
局限与注意事项
泛型擦除的本质决定了**不是所有泛型信息都能恢复**:
- 局部变量、方法内临时创建的泛型集合(如
List<string> list = new ArrayList();</string>)——无签名信息,反射不可见 - 泛型类型变量(如
<t> void foo(T t)</t>)——运行时是type variable,无法获得具体类,除非通过上下文推断或额外传参 - 数组泛型(如
List<string>[]</string>)需结合GenericArrayType处理,不能直接强转为ParameterizedType - 使用
instanceof或getClass()判断泛型实例类型永远只返回原始类型,这是擦除的必然结果
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











