在Java中,泛型信息在编译后会被擦除,这意味着在运行时无法直接获取泛型的具体类型信息,
这时候就需要Java中的TypeReference
一、java泛型擦除
如下代码
List<String> list = new ArrayList<>();
list.add("Hello");
String s = list.get(0);
编译器处理后实际生成的字节码等价于:
List list = new ArrayList(); // 原始类型
list.add("Hello"); // 添加Object
String s = (String) list.get(0); // 编译器插入的强制转换
那这里为什么编译器会自动添加类型转换呢
步骤1:编译时类型约束
List<String> list = new ArrayList<>();
-
编译器记录 list 的类型参数为 String
-
所有后续操作都基于此约束检查
步骤2:添加元素验证
list.add("Hello"); // ✅ 通过
list.add(123); // ❌ 编译失败
步骤3:获取元素转换
String s = list.get(0);
↓ 编译器转换为 ↓
String s = (String) list.get(0); // 插入强制转换
TypeReference提供了一种在运行时保留泛型类型信息的方法:
// 创建带有具体泛型信息的TypeReference
TypeReference<Map<String, String>> typeRef = new TypeReference<Map<String, String>>() {};
// 获取完整的类型信息
Type type = typeRef.getType();
System.out.println(type); // java.util.Map<java.lang.String, java.lang.String>
实际应用
常见的是json的解析中调用方法里会传入TypeRegerence参数
如果不使用TypeReference
// 编译时:Map<String, String>
// 运行时:只保留原始类型 Map
Map<String, String> map = new HashMap<>();
// 错误示例:类型信息丢失
//mapper.readValue就是把json字符串转化为第二个参数
Map<String, String> result = mapper.readValue(json, map.getClass());
在运行时,map.getClass() 返回的是 HashMap.class 或 Map.class,但不知道:
-
键的类型是 String
-
值的类型是 String
所以
-
键可能被解析为 Object 而非 String
-
值可能被解析为 Object 而非 String
解决办法就是通过TypeReference
ObjectMapper mapper = new ObjectMapper();
String json = "{\"name\":\"John\", \"age\":\"30\"}";
// 使用TypeReference保留Map类型信息
Map<String, String> result = mapper.readValue(json,
new TypeReference<Map<String, String>>() {});
匿名内部类在运行时保留了 Map<String, String> 的完整类型信息
-
Java 编译器对泛型执行类型擦除,但有一个重要例外:
-
当类/接口被继承或实现时,编译器会在字节码中保留具体的泛型参数信息
-
当创建匿名子类时:
new TypeReference<Map<String, String>>() {}Java 编译器会生成一个类似如下的类(伪代码):
class Anonymous1 extends TypeReference<Map<String, String>> {} -
这个生成的类在字节码中明确记录了父类的泛型参数
Map<String, String>。
让我们看看源码
public abstract class TypeReference<T> {
protected final Type _type;
public TypeReference() {//TypeReference的构造器
Type superClass = getClass().getGenericSuperclass();
// 获取父类(TypeReference)的泛型参数:Map<String, String>
_type = ((ParameterizedType) superClass).getActualTypeArguments()[0];
}
public Type getType() { return _type; }
}
| 方法 | 作用 | 返回值示例 |
|---|---|---|
getClass().getGenericSuperclass() | 获取当前类的泛型父类类型 | TypeReference<Map<String, String>> |
(ParameterizedType) 强转 | 转换为可提取泛型参数的类型 | 参数化类型对象 |
getActualTypeArguments()[0] | 获取父类的第一个泛型参数 |
|
在 Jackson 中的实际使用:
当调用 objectMapper.readValue() 时:
objectMapper.readValue(json, new TypeReference<Map<String, String>>() {});
Jackson 内部会调用:
TypeReference ref = ...; // 您的匿名实例
JavaType type = objectMapper.getTypeFactory().constructType(ref.getType());

1897

被折叠的 条评论
为什么被折叠?



