Java反射获取泛型类型参数需通过ParameterizedType接口,前提为泛型信息存在于类、字段声明处而非局部变量;最可靠方式是继承父类时调用getGenericSuperclass()并检查ParameterizedType。

Java 反射中获取泛型类型参数,核心是通过 ParameterizedType 接口,但必须满足“泛型信息在运行时未被完全擦除”的前提——即该泛型信息存在于类、字段或方法的**声明位置**(如继承自带泛型的父类、字段声明为泛型类型),而非局部变量或方法调用处。
从继承关系中获取父类的泛型实参
这是最常见且可靠的方式,适用于子类明确继承了参数化父类(如 class Child extends Parent<String>):
- 调用
getClass().getGenericSuperclass(),返回的是Type; - 若结果是
ParameterizedType,则可用getActualTypeArguments()获取实际类型参数数组; - 注意:数组元素仍是
Type,可能是Class(如String.class)、ParameterizedType(如List<Integer>)或TypeVariable(如T)。
示例:
class Parent<T, V> {}
class Child extends Parent<String, List<Integer>> {}
// 在 Child 实例中:
Type genericSuper = getClass().getGenericSuperclass();
if (genericSuper instanceof ParameterizedType) {
Type[] args = ((ParameterizedType) genericSuper).getActualTypeArguments();
// args[0] → String.class
// args[1] → ParameterizedType 表示 List<Integer>
}
从字段声明中获取泛型类型
当字段本身声明为泛型类型(如 private Map<String, User> data;),可通过 Field.getGenericType() 获取完整泛型信息:
立即学习“Java免费学习笔记(深入)”;
- 先用
getClass().getDeclaredField("fieldName")获取字段; - 调用
field.getGenericType(),若字段是参数化类型,则返回ParameterizedType; - 再调用
getRawType()得到原始类型(如Map.class),getActualTypeArguments()得到String.class和User.class。
注意:字段需是当前类直接声明的,继承来的私有字段无法通过 getDeclaredField 访问,且必须设 setAccessible(true) 才能读取私有字段。
解析嵌套泛型与类型变量
泛型参数可能本身是参数化类型(如 List<Map<K, V>>)或类型变量(如 T extends Number),需递归或条件判断处理:
- 对每个
Type元素,用instanceof分别检查是否为Class、ParameterizedType、TypeVariable或WildcardType; - 遇到
ParameterizedType,可继续调用getActualTypeArguments()展开; - 遇到
TypeVariable,可通过getBounds()获取上界(如T extends Comparable<T>中的Comparable),但无法知道具体实参——因为它是编译期占位符,运行时无对应类型。
不能获取的情况和常见误区
以下场景反射无法还原泛型实参,因类型信息已被擦除:
- 方法参数或返回值的泛型(除非是泛型方法且在调用处显式指定,但反射仍拿不到调用时的实参);
- 局部变量声明,如
List<String> list = new ArrayList<>();—— 编译后只剩List; - 泛型数组类型,如
List<String>[],getComponentType()返回的是擦除后的List.class; - 使用通配符且未限定,如
List<?>,反射中表现为WildcardType,但下界/上界可能为空。
不复杂但容易忽略。


















