欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 房产 > 家装 > 深入理解 `ParameterizedTypeReference`:解决 Java 泛型擦除问题

深入理解 `ParameterizedTypeReference`:解决 Java 泛型擦除问题

2025/3/14 20:47:51 来源:https://blog.csdn.net/weixin_54574094/article/details/146198276  浏览:    关键词:深入理解 `ParameterizedTypeReference`:解决 Java 泛型擦除问题

在 Java 中,由于类型擦除的存在,我们在使用 RestTemplate 获取带有泛型的 HTTP 响应时,可能会遇到 泛型信息丢失 的问题。而 ParameterizedTypeReference<T> 正是用来解决这个问题的。

本文将深入解析 ParameterizedTypeReference 的作用、原理,并结合 RestTemplate 举例说明如何正确解析泛型数据


1. 为什么 Java 需要 ParameterizedTypeReference

在 Java 中,泛型的实现采用类型擦除(Type Erasure),即:

  • 编译时 泛型信息是完整的,例如 List<String>List<Integer>
  • 运行时 泛型信息被擦除,所有泛型类型都会变成 List,无法区分 List<String>List<Integer>

示例:Java 运行时擦除泛型

List<String> list1 = new ArrayList<>();
List<Integer> list2 = new ArrayList<>();System.out.println(list1.getClass() == list2.getClass()); // true

输出:

true

可以看出,List<String>List<Integer> 在运行时完全相同。


2. RestTemplate 解析泛型数据时的问题

假设我们有一个 API /api/users,返回 JSON 数据如下:

{"code": "SUCCESS","message": "请求成功","data": [{"id": 1,"name": "Alice"},{"id": 2,"name": "Bob"}]
}

对应的 Java 数据模型

import lombok.Data;
import java.util.List;@Data
class User {private Integer id;private String name;
}@Data
class BaseResponse<T> {private String code;private String message;private T data;
}

尝试使用 RestTemplate 获取泛型数据

ResponseEntity<BaseResponse<List<User>>> response = restTemplate.exchange(url,HttpMethod.GET,entity,BaseResponse<List<User>>.class  // ❌ 这里会导致类型擦除
);

问题: BaseResponse<List<User>>.class 在运行时 会被擦除成 BaseResponse<Object>,导致 JSON 反序列化失败!

解决方案? ✅ 使用 ParameterizedTypeReference


3. 使用 ParameterizedTypeReference 解析泛型数据

ParameterizedTypeReference<T> 的作用是 保留泛型信息,从而让 RestTemplate 正确解析带泛型的 JSON 数据。

✅ 正确写法

import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.*;
import org.springframework.web.client.RestTemplate;
import java.util.List;public class RestTemplateExample {private static final RestTemplate restTemplate = new RestTemplate();public static void main(String[] args) {String url = "https://example.com/api/users";// 创建请求头HttpHeaders headers = new HttpHeaders();headers.setContentType(MediaType.APPLICATION_JSON);// 创建请求实体HttpEntity<String> entity = new HttpEntity<>(null, headers);// 使用 ParameterizedTypeReference 获取泛型数据ResponseEntity<BaseResponse<List<User>>> response = restTemplate.exchange(url,HttpMethod.GET,entity,new ParameterizedTypeReference<BaseResponse<List<User>>>() {} // ✅ 保留泛型信息);// 解析返回数据if (response.getStatusCode() == HttpStatus.OK) {BaseResponse<List<User>> body = response.getBody();if (body != null && "SUCCESS".equals(body.getCode())) {List<User> users = body.getData();users.forEach(user -> System.out.println(user.getName()));}}}
}

ParameterizedTypeReference<T> 解决了什么?

  • 保留了 BaseResponse<List<User>> 的泛型信息,避免 Java 类型擦除
  • RestTemplate 解析 JSON 时,知道 data 字段实际是 List<User>,从而正确反序列化。

4. ParameterizedTypeReference 的底层原理

我们来看 ParameterizedTypeReference核心源码

public abstract class ParameterizedTypeReference<T> {private final Type type;protected ParameterizedTypeReference() {this.type = ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];}public Type getType() {return this.type;}
}

原理解析

  1. ParameterizedTypeReference<T>抽象类,不能直接实例化。
  2. new ParameterizedTypeReference<BaseResponse<List<User>>>() {} 实际上是 匿名内部类,继承 ParameterizedTypeReference<T>
  3. 构造方法 中:
    • 通过 getClass().getGenericSuperclass() 获取 ParameterizedType
    • getActualTypeArguments()[0] 解析出 BaseResponse<List<User>>,并存储到 type 变量中。
  4. 这样,type 变量在运行时 不会被擦除,Spring 通过 type 解析泛型 JSON 数据。

5. 适用场景

适用于解析带泛型的 JSON 响应

  • List<T>Map<String, T>Set<T>复杂数据结构
  • 适用于 Spring WebClient 以及 消息队列(Kafka)等泛型解析

示例:解析 Map<String, List<User>>

ResponseEntity<BaseResponse<Map<String, List<User>>>> response = restTemplate.exchange(url,HttpMethod.GET,entity,new ParameterizedTypeReference<BaseResponse<Map<String, List<User>>>>() {}
);

ParameterizedTypeReference 还能解析更复杂的泛型结构,如 Map<String, List<User>>,Spring 能够正确识别 data 的数据结构!


6. 总结

  • Java 运行时会擦除泛型,导致 RestTemplate 无法正确解析泛型 JSON。
  • ParameterizedTypeReference<T> 通过匿名内部类的方式 保留泛型信息,解决类型擦除问题。
  • 适用于 RestTemplateWebClientKafka 消费者Redis 泛型缓存 等场景

建议:在 RestTemplate 解析泛型数据时,务必使用 ParameterizedTypeReference,否则 JSON 解析可能失败!


希望这篇博客能帮助你理解 ParameterizedTypeReference 的作用和应用场景!🎯

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词