You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Mockito两种泛型any写法区别及RestTemplate mock编译报错原因

Mockito泛型匹配编译问题原理详解

核心差异点

二者的静态类型完全不同:

  • Mockito.<ServiceResponse>any().getClass()的静态返回类型是 Class<? extends ServiceResponse>
  • Mockito.<Class<ServiceResponse>>any()的静态返回类型是 Class<ServiceResponse>

为什么原代码编译报错

首先看RestTemplate.exchange()方法的核心泛型签名:

<T> ResponseEntity<T> exchange(String url, HttpMethod method, HttpEntity<?> requestEntity, Class<T> responseType, Map<String, ?> uriVariables)

方法的第四个参数responseType的泛型和返回值ResponseEntity<T>的泛型是绑定的。
你传入Mockito.<ServiceResponse>any().getClass()作为第四个参数时,因为Java语言规范规定Object.getClass()的返回类型固定为Class<? extends 调用对象的静态类型>,此时编译器会将泛型参数T推断为? extends ServiceResponse,对应的exchange返回值类型为ResponseEntity<? extends ServiceResponse>。
而泛型具备不变性:ResponseEntity<ServiceResponse>和ResponseEntity<? extends ServiceResponse>是完全无关的两个类型,你调用thenReturn(ResponseEntity.ok(expectedResponse))传入的是ResponseEntity<ServiceResponse>,和方法期望的参数类型不匹配,就会抛出编译错误。
你可以通过这个简单的示例理解getClass()的类型规则:

String str = "demo";
// 编译正确,getClass()返回的是带通配符上界的类型
Class<? extends String> cls1 = str.getClass();
// 编译直接报错,无法把Class<? extends String>赋值给Class<String>
Class<String> cls2 = str.getClass();

为什么替换后编译正常

你替换为Mockito.<Class<ServiceResponse>>any()后,第四个参数的静态类型就是严格的Class<ServiceResponse>,完全匹配exchange方法的第四个参数泛型要求,此时编译器会将T准确推断为ServiceResponse,对应的exchange返回值类型为ResponseEntity<ServiceResponse>,和你thenReturn传入的参数类型完全一致,自然编译通过。

认知误区修正

你认为「ServiceResponse的类就是Class<ServiceResponse>」这个认知本身是正确的,错误点在于你误以为Mockito.<ServiceResponse>any().getClass()能拿到Class<ServiceResponse>类型,实际上Java的getClass()方法返回值固定带通配符上界,这个是语言层面为了兼容运行时多态做的设计,和你调用对象的静态类型无关。

内容的提问来源于stack exchange,提问作者ng.newbie

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.30 04:39:03