使用assertThat+is匹配short类型时出现NoSuchMethodError问题
这个错误的核心是Java自动装箱/拆箱机制与Hamcrest泛型Matcher的类型兼容性冲突,具体拆解如下:
1. 类型不匹配的根源
你的order.status是short类型,调用assertThat时会被自动装箱为Short对象;而is(0)里的0是默认的int类型,会被装箱为Integer对象,此时is方法返回的是Matcher<Integer>类型的匹配器。
Hamcrest的assertThat方法要求匹配器的类型是Matcher<? super T>(T是实际值的类型,这里是Short)。但泛型不支持跨子类的协变——Integer和Short虽然都是Number的子类,但Matcher<Integer>和Matcher<Short>之间没有继承关系。编译时因为泛型擦除不会报错,但运行时会出现方法签名不匹配的问题。
2. NoSuchMethodError的具体触发逻辑
运行时JVM尝试调用适配Short类型的Matcher.describeMismatch(Object, Description)方法,但实际传入的是适配Integer的Matcher。由于Hamcrest内部会根据泛型实际类型做校验,导致找不到对应签名的方法实现,最终抛出NoSuchMethodError。
3. 强制转成(short)0生效的原因
当你把0强制转换为short类型后,它会被装箱为Short对象,此时is方法返回的是Matcher<Short>类型的匹配器,完全符合assertThat的类型要求。运行时JVM能找到正确的describeMismatch方法,错误自然消失。
额外说明:编译时无报错的原因
Java编译器处理泛型时会做类型擦除,Matcher<Integer>和Matcher<Short>擦除后都是Matcher类型,所以编译器不会拦截这个问题,但运行时Hamcrest的类型校验会暴露冲突。
内容的提问来源于stack exchange,提问作者Svish

