2015-11-26 21 views
20

Si consideri il seguente caso di test con lo standard JUnit afferma e hamcrest di assertThat:Perché hamcrest dice che un byte 0 non è uguale a un 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 
} 

Perché è così? I valori sono apparentemente uguali per JVM perché b == i è true, quindi perché hamcrest non riesce?

+6

Perché 'Byte.valueOf ((byte) 0) .equals (Integer.valueOf (0))' è falso. – assylias

+1

Come visto nell'esempio * assylias * 'sopra, il byte diventa auto-box in un oggetto Byte. Come si può vedere nella [same Hamstest docs] di Hamcrest (http://hamcrest.org/JavaHamcrest/javadoc/1.3/org/hamcrest/core/IsEqual.html#equalTo (T)) utilizza Object1.equals (Object2). Poiché sia ​​il byte che l'int sono primitivi, li auto-li impacchetta in oggetti Byte e Integer. Byte1.equals (Intero1) restituirà false, anche se i valori di questi oggetti box sono uguali. –

risposta

28

Assert#assertThat è un metodo generico. I tipi primitivi non funzionano con i generici. In questo caso, lo e sono inseriti rispettivamente in Byte e Integer.

diventa quindi (entro assertThat)

Byte b = 0; 
Integer i = 0; 

b.equals(i); 

s' Byte#equals(Object) controlli di implementazione se l'argomento è di tipo Byte, tornando false immediatamente se non lo è.

D'altra parte, è assertEqualsAssert#assertEquals(long, long) nel qual caso entrambe le byte e int argomenti sono promossi al long valori. Internamente, questo utilizza == su due valori primitivi long uguali.


Si noti che questa conversione boxe funziona perché assertThat è dichiarato come

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

dove il byte è inscatolato ad un Byte per T, e il int è una scatola a un Integer (all'interno della chiamata a equalTo), ma dedotto come Number per corrispondere allo Matcher<? super T>.

Questo funziona con inferenza generica migliorata di Java 8. Avreste bisogno di argomenti di tipo esplicite per farlo funzionare in Java 7.

13

Questo accade perché la int e byte sono boxed per Integer e Byte come matchers hamcrest operano su oggetti, non su primitive. Così si sta confrontando un Integer con un Byte, e l'implementazione di Byte.equals() è:

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

e Integer.equals():

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

In altre parole, un Integer e Byte sono sempre disuguale. Quando si confrontano le primitive, utilizzare invece Assert.assertEquals. Gli hamcrest matcher sono potenti, ma principalmente pensati per (complesse) asserzioni di oggetti.

+0

C'è qualche motivo per Java per non verificare i valori nello stesso intervallo? Per esempio. 'if (obj instanceof Integer) {return ((Integer) obj) .intValue() == (int) valore;}' in 'Byte.equals()'? – sina

+0

@sina Bene, questa è probabilmente la ragione per cui abbiamo le primitive che possiamo usare. Quando Java confronta due oggetti, prima controlla se entrambi gli oggetti sono dello stesso tipo; se no, restituisce semplicemente false. 'Integer' e' Byte' sono oggetti, quindi lo stesso vale per loro. Se '(new Byte (0)). Equals (new Integer (0))' restituisce true, sarebbe un po 'strano per me. Un esempio comparabile sarebbe se '(new Dog (" Luke ")). Equals (new Cat (" Luke "))' restituisce true, semplicemente perché hanno lo stesso nome (lo so, non è il miglior esempio qui, ma poi vedi come sembra strano se sarebbe tornato vero). –

+0

@KevinCruijssen È una cosa che non ti aspetti quando la boxe accade. Si potrebbe obiettare che 'Number' potrebbe richiedere un uguaglianza che permette che' Integer' e 'Byte' siano comparabili, ma che probabilmente porterebbero a un comportamento inaspettato con' Float' e 'Double' o un'implementazione molto complessa da tenere in considerazione 'altri' tipi di numeri. –