2015-11-26 7 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 
} 

だから、なぜでしょうか? b == itrueなので、値は明らかにJVMで等しいので、hamcrestはなぜ失敗しますか?

+6

Byte.valueOf((byte)0).equals(Integer.valueOf(0))はfalseです。 – assylias

+1

上記の* assylias *の例に見られるように、バイトは自動ボックス化されてByteオブジェクトになります。 [HamcrestのequalToドキュメント](http://hamcrest.org/JavaHamcrest/javadoc/1.3/org/hamcrest/core/IsEqual.html#equalTo(T))に見られるように、Object1.equals(Object2)を使用します。 byteとintの両方がプリミティブなので、それらをByteオブジェクトとIntegerオブジェクトにオートボックスします。 Byte1。これらの囲みオブジェクトの値が同じであっても、equals(Integer1)はfalseを返します。 –

答えて

28

Assert#assertThatは一般的な方法です。プリミティブ型はジェネリックでは機能しません。この場合、byteintはそれぞれByteIntegerに囲まれています。

引数がそうでない場合は、直ちにfalseを返す、タイプByteである場合には、次に(assertThat内)

Byte b = 0; 
Integer i = 0; 

b.equals(i); 

Byte#equals(Object)の実装チェックなります。一方

assertEquals両方byteint引数がlong値に昇格された場合にAssert#assertEquals(long, long)あります。内部的には、これは等しい2つのプリミティブlong値に対して==を使用します。 assertThatbyteTためByteに箱詰めさ

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

として宣言されているので、このボクシング変換が動作し、intがへの呼び出し内(Integerに箱詰めされていることを


equalTo)が、として、Matcher<? super T>に一致すると推測されます。

これはJava 8の改良された汎用推論で機能します。あなたはそれがhamcrestのマッチャーは、オブジェクト上ではなく、プリミティブで動作するようintbyteIntegerByteに箱詰めされているので、これが起こる

13

のJava 7で動作するように明示的な型の引数を必要とするだろう。だから、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 matcherは強力ですが、主に(複雑な)オブジェクトアサーションを対象としています。

+0

Javaが同じ範囲の値をチェックしない理由はありますか?例えば。 Byte.equals()の 'if(obj instanceof Integer){return((Integer)obj).intValue()==(int)value;}'? – sina

+0

@sinaこれはおそらく、私たちが代わりに使うことができるプリミティブを持っている理由でしょう。 Javaは2つのオブジェクトを比較すると、最初に両方のオブジェクトが同じ型であるかどうかをチェックします。もしそうでなければ、単にfalseを返します。 'Integer'と' Byte'はオブジェクトなので、同じことがそれらに適用されます。 '(new Byte(0))。equals(new Integer(0))'がtrueを返すと、それは私にはちょっと変わってしまうでしょう。同様の例は '(新しいDog(" Luke "))。equals(new Cat(" Luke "))'が同じ名前を持つため単純にtrueを返す場合です(私はここで最良の例ではありませんが、それが真実に戻ってくるかどうか、あなたはどのように奇妙に見えますか)。 –

+0

@KevinCruijssenボクシングが起こるときにあなたが期待していないことです。 'Number'は' Integer'と 'Byte'を比較可能にする等号を必要とするかもしれないと主張するかもしれませんが、' Float'や 'Double'や非常に複雑な実装を考えると予期しない動作につながるでしょう'その他'の数字の種類。 –

関連する問題