2015-11-26 39 views
20

使用标准考虑下面的测试案例JUnit断言和hamcrest的assertThat为什么hamcrest说一个字节0不等于一个int 0?

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 
} 

为什么会这样呢? JVM的值显然是相等的,因为b == itrue,所以为什么hamcrest失败?

+6

因为Byte.valueOf((byte)0).equals(Integer.valueOf(0))'为false。 – assylias

+1

如上面的* assylias *'例子所示,该字节被自动装箱成一个字节对象。如[Hamcrest的equalTo文档](http://hamcrest.org/JavaHamcrest/javadoc/1.3/org/hamcrest/core/IsEqual.html#equalTo(T))所示,它使用Object1.equals(Object2)。既然byte和int都是原语,它会自动将它们装入Byte和Integer对象。字节1。等于(Integer1)将返回false,即使这些盒装对象的值是相同的。 –

回答

28

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

然后,它变成(内assertThat

Byte b = 0; 
Integer i = 0; 

b.equals(i); 

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

在另一方面,assertEqualsAssert#assertEquals(long, long)在这种情况下两个byteint参数都提升到long值。在内部,这使用==两个相同的原始值long值。


注意,该装箱转换工作,因为assertThat被声明为

public static <T> void assertThat(T actual, Matcher<? super T> matcher) { 

其中byte是盒装的ByteT,并且int是盒装到Integer(调用内equalTo),但推断为Number以匹配Matcher<? super T>

这适用于Java 8的改进通用推断。你需要显式类型的参数,使其在Java 7中工作

13

这是因为intbyte被装箱为IntegerByte作为hamcrest匹配器操作的对象,而不是原语。所以,你是一个比较ByteInteger,并Byte.equals()实现如下:

public boolean equals(Object obj) { 
    if (obj instanceof Byte) { 
     return value == ((Byte)obj).byteValue(); 
    } 
    return false; 
} 

Integer.equals()

public boolean equals(Object obj) { 
    if (obj instanceof Integer) { 
     return value == ((Integer)obj).intValue(); 
    } 
    return false; 
} 

换句话说,一个IntegerByte总是不等。在比较原语时,只需使用Assert.assertEquals。 Hamcrest匹配器功能强大,但主要用于(复杂)对象声明。

+0

Java是否有任何理由不检查相同范围内的值?例如。 if(obj instanceof Integer){return((Integer)obj).intValue()==(int)value;}'in'Byte.equals()'? – sina

+0

@sina好吧,这可能是我们有原始代码可以使用的原因。当Java比较两个对象时,它首先检查两个对象是否具有相同的类型;如果不是,它只是返回false。 “整数”和“字节”是对象,所以它们也是一样。如果'(new Byte(0))。equals(new Integer(0))'会返回true,那对我来说会有点奇怪。一个可比的例子是,如果'(新的狗(“卢克”))等于(新的猫(“卢克”))将返回true,仅仅因为他们有相同的名称(我知道,这里不是最好的例子,但那么你会看到它看起来有多奇怪,如果它会返回true)。 –

+0

@KevinCruijssen这是一件你不会期待拳击发生的事情。有人可能会争辩说,Number可能需要一个等于'Integer'和'Byte'的equals,但这可能会再次导致出现意外的行为,以'Float'和'Double'或非常复杂的实现来考虑'其他'号码类型。 –

相关问题