泛型与反射
类型擦除后运行时无泛型信息,但反射可获取部分泛型签名。
获取字段泛型类型
Java
public class MyClass {
private List<String> stringList;
private Map<String, Integer> map;
}
// 获取字段的泛型类型
Field field = MyClass.class.getDeclaredField("stringList");
Type genericType = field.getGenericType();
if (genericType instanceof ParameterizedType) {
ParameterizedType pt = (ParameterizedType) genericType;
Type rawType = pt.getRawType(); // List.class
Type[] actualTypes = pt.getActualTypeArguments();
System.out.println(actualTypes[0]); // String.class
}
获取方法泛型类型
Java
public class MyClass {
public List<String> getList() { return null; }
public void setMap(Map<String, Integer> map) {}
}
// 获取返回类型泛型
Method method = MyClass.class.getMethod("getList");
Type returnType = method.getGenericReturnType();
if (returnType instanceof ParameterizedType) {
ParameterizedType pt = (ParameterizedType) returnType;
Type[] actualTypes = pt.getActualTypeArguments();
System.out.println(actualTypes[0]); // String.class
}
// 获取参数类型泛型
Method setMapMethod = MyClass.class.getMethod("setMap", Map.class);
Type[] paramTypes = setMapMethod.getGenericParameterTypes();
// paramTypes[0] 是 ParameterizedType
ParameterizedType 接口
Java
public interface ParameterizedType extends Type {
Type[] getActualTypeArguments(); // 实际类型参数
Type getRawType(); // 原始类型
Type getOwnerType(); // 所属类型(嵌套时)
}
| 方法 | 说明 |
|---|---|
| getActualTypeArguments() | 获取泛型参数类型数组 |
| getRawType() | 获取原始类型(如 List) |
| getOwnerType() | 获取外部类类型(嵌套类) |
Type 接口体系
Java
Type(接口)
├── Class // 普通类
├── ParameterizedType // 参数化类型 List<String>
├── GenericArrayType // 泛型数组 T[]
├── TypeVariable // 类型变量 T
└── WildcardType // 通配符 ?
获取继承的泛型信息
Java
public abstract class BaseDao<T> {
private Class<T> entityClass;
public BaseDao() {
// 获取子类继承时指定的泛型类型
Type type = getClass().getGenericSuperclass();
if (type instanceof ParameterizedType) {
ParameterizedType pt = (ParameterizedType) type;
this.entityClass = (Class<T>) pt.getActualTypeArguments()[0];
}
}
public Class<T> getEntityClass() {
return entityClass;
}
}
// 子类指定泛型类型
public class UserDao extends BaseDao<User> {}
// 使用
UserDao userDao = new UserDao();
Class<User> entityClass = userDao.getEntityClass(); // User.class
典型应用:框架中 DAO、Service 基类通过反射获取子类指定的泛型类型。
TypeToken(Gson)
Google Gson 使用 TypeToken 解决泛型擦除问题:
text
// 普通方式:无法获取 List<String> 类型
Type type = new TypeToken<List<String>>() {}.getType();
// 解析 JSON 为泛型集合
List<String> list = gson.fromJson(json, type);
TypeToken 通过匿名类保留泛型签名,反射获取。
泛型信息保留位置
| 位置 | 保留泛型信息 |
|---|---|
| 类字段 | ✅ Signature 属性 |
| 方法参数 | ✅ Signature 属性 |
| 方法返回类型 | ✅ Signature 属性 |
| 类继承 | ✅ Signature 属性 |
| 运行时对象 | ❌ 已擦除 |
| 局部变量 | ❌ 不保留 |
Signature 属性:编译器在字节码中存储泛型签名,反射可读取。
要点总结
- 泛型擦除后反射可通过 Signature 获取部分信息
- getGenericType() 返回 Type(可能是 ParameterizedType)
- ParameterizedType.getActualTypeArguments() 获取泛型参数
- 字段、方法参数、返回类型、继承保留泛型签名
- 运行时对象和局部变量不保留泛型信息
- 典型应用:框架基类获取子类指定的泛型类型
- TypeToken(Gson)通过匿名类保留泛型签名
📝 发现内容有误?点击此处直接编辑