2015-11-26 40 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'或非常複雜的實現來考慮'其他'號碼類型。 –

相關問題