为什么hamcrest说字节0不等于int 0?

sin*_*ina 22 java junit hamcrest

考虑使用标准JUnit断言和hamcrest的以下测试用例assertThat:

byte b = 0;
int i = 0;

assertEquals(b, i); // success
assertThat(b, equalTo(i)); // java.lang.AssertionError: Expected: <0> but: was <0>

if (b == i) {
    fail(); // test fails, so b == i is true for the JVM
}
Run Code Online (Sandbox Code Playgroud)

为什么会这样?对于JVM b == i来说true,这些值显然是相同的,因为为什么会hamcrest失败?

Sot*_*lis 29

Assert#assertThat是一种通用方法.原始类型不适用于泛型.在这种情况下,byteint将分别加到ByteInteger.

然后变成(内assertThat)

Byte b = 0;
Integer i = 0;

b.equals(i);
Run Code Online (Sandbox Code Playgroud)

Byte#equals(Object)的实现检查参数是否为类型Byte,false如果不是,则立即返回.

在另一方面,assertEquals就是Assert#assertEquals(long, long)在这种情况下,无论是byteint参数都提升到long价值观.在内部,它使用==两个long相等的原始值.


请注意,此拳击转换有效,因为assertThat声明为

public static <T> void assertThat(T actual, Matcher<? super T> matcher) {
Run Code Online (Sandbox Code Playgroud)

在哪里byte被装箱为一个Bytefor T,并且int是一个盒装到一个Integer(在通话中equalTo),但推断为一个Number匹配的Matcher<? super T>.

这适用于Java 8改进的通用推理.您需要显式类型参数才能使其在Java 7中运行.


Mar*_*eel 13

之所以会发生这种情况int,byte是因为它们被装箱Integer并且Byte作为hamcrest匹配器在对象上操作,而不是在基元上操作.所以你要比较a Integer和a Byte的实现Byte.equals()是:

public boolean equals(Object obj) {
    if (obj instanceof Byte) {
        return value == ((Byte)obj).byteValue();
    }
    return false;
}
Run Code Online (Sandbox Code Playgroud)

并且Integer.equals():

public boolean equals(Object obj) {
    if (obj instanceof Integer) {
        return value == ((Integer)obj).intValue();
    }
    return false;
}
Run Code Online (Sandbox Code Playgroud)

换句话说,一个Integer并且Byte总是不平等的.比较基元时,只需使用Assert.assertEquals.hamcrest匹配器功能强大,但主要用于(复杂)对象断言.