Java泛型擦除后仍可通过反射获取声明处的泛型信息:字段、父类继承、方法签名中的泛型实参可由getGenericType()、getGenericSuperclass()、getGenericReturnType()等API提取,但局部变量和new表达式中的泛型信息完全丢失。

Java 的泛型擦除机制意味着:运行时没有泛型类型信息。List<string></string> 和 List<integer></integer> 编译后都是 List,JVM 加载的字节码里不保留 <string></string> 这类标记。但这不等于“完全无迹可寻”——只要泛型信息出现在类结构声明位置(如字段、父类继承、方法签名),它就会保留在字节码的 Signature 属性中,可通过反射提取。
下面说几个真正能用、不踩坑的处理方式:
从字段声明中读取泛型实参
字段若带泛型(比如 private Map<string user> cache;</string>),其完整类型在编译时被记录,运行时可用:
-
field.getGenericType()返回ParameterizedType(不是field.getType(),后者只返回Map.class) - 判断后强转:
((ParameterizedType) type).getActualTypeArguments()得到{String.class, User.class} - 注意:通配符(如
? extends Number)需用WildcardType接口进一步调用getUpperBounds()
通过父类继承关系还原泛型类型
子类显式指定父类泛型时(如 class OrderDao extends BaseDao<order></order>),JVM 会把 BaseDao<order></order> 作为泛型父类签名写入字节码:
-
this.getClass().getGenericSuperclass()返回ParameterizedType -
getActualTypeArguments()[0]就是Order.class - 这是 MyBatis、Spring Data JPA 自动推断实体类的核心原理
解析方法参数或返回值的嵌套泛型
接口方法若声明了复杂泛型(如 public Response<list>> search()</list>),其签名完整保留:
-
method.getGenericReturnType()获取Response<list>></list>对应的ParameterizedType - 递归解析:先取
Response的实参List<product></product>,再从中取Product.class - 遇到
TypeVariable(如方法自身的<t> T get()</t>中的T),无法直接还原,需结合类级泛型上下文判断
避免常见误操作
- ❌ 不要用
instanceof List<string></string>:语法不合法,只能写instanceof List - ❌ 不要依赖局部变量或方法返回值的泛型:
List<string> list = new ArrayList();</string>中的<string></string>完全丢失,反射也拿不到 - ❌ 不要指望
new T()或T[].class:擦除后T不存在,必须显式传入Class<t></t>或用Supplier<t></t>替代
本质上,运行时“找回”泛型信息,靠的不是恢复擦除内容,而是提前把类型信息锚定在结构声明处,再用反射去挖。不复杂但容易忽略。
立即学习“Java免费学习笔记(深入)”;


















