java泛型在运行时通过signature属性保留声明位置的类型信息,反射可获取字段、父类继承、方法参数/返回值中的泛型实参,需用getgenerictype等方法并判断parameterizedtype等类型,谨慎处理通配符与typevariable。

Java泛型在运行时确实被擦除,但“擦除”不等于“彻底消失”——只要泛型信息出现在类结构的声明位置(如字段、方法签名、父类继承),JVM 就会把它保留在字节码的 Signature 属性中。反射能拿到的,正是这部分未被擦除的元数据。关键不是“对象实例”,而是“声明上下文”。
从字段声明中提取泛型实参
这是最常用、最稳定的入口。字段类型若带泛型(如 private ListField.getGenericType() 获取。
- 调用
field.getGenericType()得到的是Type接口,需先判断是否为ParameterizedType - 是则强转,再调用
getActualTypeArguments()获取类型数组,例如List<user></user>返回长度为 1 的数组,首元素即User.class - 注意:不能用
field.getType(),它返回擦除后的List.class,毫无泛型信息
通过父类继承关系获取泛型类型
当子类显式指定父类泛型(如 class UserDao extends BaseDao
- 调用
getClass().getGenericSuperclass(),而非getSuperclass()(后者只返回擦除后的BaseDao.class) - 若返回值是
ParameterizedType,用getActualTypeArguments()[0]即可拿到User.class - 适用于抽象基类封装通用逻辑的场景,代码一次写好,子类无需重复传类型
解析方法参数与返回值的泛型
接口或类中定义的方法,若参数或返回值含泛型(如 public Map
- 用
method.getGenericReturnType()或getGenericParameterTypes()获取Type数组 - 对每个元素做
instanceof ParameterizedType判断;若是,递归处理其getActualTypeArguments() - 嵌套泛型如
Map<string list>></string>需两层解析:先取Map的第二个参数(List<integer></integer>),再从中取Integer.class
处理特殊类型:通配符与类型变量
泛型实参不总是具体类。遇到 ?、? extends Number 或方法泛型 <t> T get()</t> 中的 T,需额外判断类型边界。
-
WildcardType可调用getUpperBounds()(默认Object.class)或getLowerBounds()(用于? super X) -
TypeVariable在运行时无具体类型,无法直接还原;需结合上下文约定(如方法所在类的泛型声明)或外部传入TypeToken辅助推断 - 避免对
TypeVariable强转为Class,否则抛ClassCastException










