Mockito两种泛型any写法区别及RestTemplate mock编译报错原因
核心差异点
二者的静态类型完全不同:
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

