2012-01-08 17 views
167

Quando si confrontano gli array in Java, ci sono delle differenze tra le seguenti 2 affermazioni?equivale a Arrays.equals in Java

array1.equals(array2); 
Arrays.equals(array1, array2); 

E se sì, quali sono?

risposta

249

array1.equals(array2) è lo stesso di array1 == array2, ovvero la stessa matrice. Come sottolinea @alf, non è quello che la maggior parte della gente si aspetta.

Arrays.equals(array1, array2) confronta il contenuto degli array.


Allo stesso modo array.toString() non può essere molto utile ed è necessario utilizzare Arrays.toString(array).

+48

Si noti che 'Arrays.equals()' non funziona come previsto per gli array multidimensionali, confronta solo gli elementi della prima dimensione per l'uguaglianza di riferimento. Apache commons 'ArrayUtils.isEquals' funziona con array multidimensionali. –

+3

Sono stordito. Esiste un motivo per cui array.equals deve essere implementato al confronto tra puntatori piuttosto che confrontare la lunghezza e ogni oggetto? – Lake

+2

@Lake è confronta la lunghezza dell'array e gli oggetti contenuti, ma ciò che non fa è un confronto approfondito. Il fatto è uguale funziona come previsto per gli array è rotto, questo non dovrebbe essere un problema in primo luogo. –

71

È un problema infame: .equals() per gli array è gravemente rotto, basta non usarlo, mai.

Detto questo, non è "rotto" come in "qualcuno lo ha fatto in un modo veramente sbagliato" - sta solo facendo ciò che è definito e non ciò che è solitamente previsto. Quindi per i puristi: è perfettamente a posto, e questo significa anche che non lo uso mai, .

Ora il comportamento previsto per equals consiste nel confrontare i dati. Il comportamento predefinito è di confrontare l'identità, poiché Object non ha dati (per i puristi: sì, ma non è il punto); l'ipotesi è, se hai bisogno di equals in sottoclassi, la implementi. Negli array, non c'è implementazione per te, quindi non dovresti usarlo.

Quindi la differenza è, Arrays.equals(array1, array2) funziona come ci si aspetterebbe (cioè confronta il contenuto), array1.equals(array2) ricade al Object.equals implementazione, che a sua volta mette a confronto l'identità, e quindi meglio sostituito da == (per i puristi: sì, lo so su null).

Il problema è che anche Arrays.equals(array1, array2) ti morderà forte se gli elementi dell'array non implementano correttamente equals. È una dichiarazione molto ingenua, lo so, ma c'è un caso molto meno che ovvio: si consideri un array 2D.

L'array 2D in Java è una matrice di matrici e gli array 'equals sono danneggiati (o inutili se si preferisce), quindi Arrays.equals(array1, array2) non funzionerà come previsto dagli array 2D.

Spero che questo aiuti.

+11

Non è rotto, è solo ereditato da Object. –

+1

In realtà non risponde alla domanda. Questo è più di un commento. – AlanFoster

+0

Un array ha un'implementazione personalizzata per 'equals()'? Ho pensato che non fosse stato scavalcato da Object. –

0

Lo equals() degli array è ereditato da Object, quindi non guarda il contenuto degli arrrays, considera solo ogni array uguale a se stesso.

I metodi Arrays.equals()do confrontano i contenuti degli array. Esistono sovraccarichi per tutti i tipi primitivi e quello per gli oggetti utilizza i metodi propri degli oggetti equals().

+2

si dice "contenuti array", significa array multidimensionali troppo? – AlanFoster

+0

@AlanFoster: no. array multidimensionali sono array di array, che significa metodo che Arrays.equals (Object [], Object []) viene invocato, che chiama uguali sub-array() metodi –

1

Il Arrays.equals(array1, array2):

controllo se entrambe le matrici contengono lo stesso numero di elementi, e tutte le corrispondenti coppie di elementi nelle due matrici sono uguali.

Il array1.equals(array2):

confronta l'oggetto a un altro e restituisce vero solo se il riferimento dei due oggetti sono uguali come nelle Object.equals()

5

Arrays ereditano equals() da Object e quindi confrontare restituisce vero solo se confrontando un array contro se stesso.

D'altra parte, Arrays.equals confronta gli elementi degli array.

Questo frammento chiarisce la differenza:

Object o1 = new Object(); 
Object o2 = new Object(); 
Object[] a1 = { o1, o2 }; 
Object[] a2 = { o1, o2 }; 
System.out.println(a1.equals(a2)); // prints false 
System.out.println(Arrays.equals(a1, a2)); // prints true 

Vedi anche Arrays.equals(). Un altro metodo statico potrebbe anche essere di interesse: Arrays.deepEquals().

15

Controllare l'interno della realizzazione dei due metodi per capirle a fondo:

array1.equals(array2); 
/** 
* Indicates whether some other object is "equal to" this one. 
* <p> 
* The {@code equals} method implements an equivalence relation 
* on non-null object references: 
* <ul> 
* <li>It is <i>reflexive</i>: for any non-null reference value 
*  {@code x}, {@code x.equals(x)} should return 
*  {@code true}. 
* <li>It is <i>symmetric</i>: for any non-null reference values 
*  {@code x} and {@code y}, {@code x.equals(y)} 
*  should return {@code true} if and only if 
*  {@code y.equals(x)} returns {@code true}. 
* <li>It is <i>transitive</i>: for any non-null reference values 
*  {@code x}, {@code y}, and {@code z}, if 
*  {@code x.equals(y)} returns {@code true} and 
*  {@code y.equals(z)} returns {@code true}, then 
*  {@code x.equals(z)} should return {@code true}. 
* <li>It is <i>consistent</i>: for any non-null reference values 
*  {@code x} and {@code y}, multiple invocations of 
*  {@code x.equals(y)} consistently return {@code true} 
*  or consistently return {@code false}, provided no 
*  information used in {@code equals} comparisons on the 
*  objects is modified. 
* <li>For any non-null reference value {@code x}, 
*  {@code x.equals(null)} should return {@code false}. 
* </ul> 
* <p> 
* The {@code equals} method for class {@code Object} implements 
* the most discriminating possible equivalence relation on objects; 
* that is, for any non-null reference values {@code x} and 
* {@code y}, this method returns {@code true} if and only 
* if {@code x} and {@code y} refer to the same object 
* ({@code x == y} has the value {@code true}). 
* <p> 
* Note that it is generally necessary to override the {@code hashCode} 
* method whenever this method is overridden, so as to maintain the 
* general contract for the {@code hashCode} method, which states 
* that equal objects must have equal hash codes. 
* 
* @param obj the reference object with which to compare. 
* @return {@code true} if this object is the same as the obj 
*   argument; {@code false} otherwise. 
* @see  #hashCode() 
* @see  java.util.HashMap 
*/ 
public boolean equals(Object obj) { 
    return (this == obj); 
} 

mentre:

Arrays.equals(array1, array2); 
/** 
* Returns <tt>true</tt> if the two specified arrays of Objects are 
* <i>equal</i> to one another. The two arrays are considered equal if 
* both arrays contain the same number of elements, and all corresponding 
* pairs of elements in the two arrays are equal. Two objects <tt>e1</tt> 
* and <tt>e2</tt> are considered <i>equal</i> if <tt>(e1==null ? e2==null 
* : e1.equals(e2))</tt>. In other words, the two arrays are equal if 
* they contain the same elements in the same order. Also, two array 
* references are considered equal if both are <tt>null</tt>.<p> 
* 
* @param a one array to be tested for equality 
* @param a2 the other array to be tested for equality 
* @return <tt>true</tt> if the two arrays are equal 
*/ 
public static boolean equals(Object[] a, Object[] a2) { 
    if (a==a2) 
     return true; 
    if (a==null || a2==null) 
     return false; 

    int length = a.length; 
    if (a2.length != length) 
     return false; 

    for (int i=0; i<length; i++) { 
     Object o1 = a[i]; 
     Object o2 = a2[i]; 
     if (!(o1==null ? o2==null : o1.equals(o2))) 
      return false; 
    } 

    return true; 
} 
7

Sigh. Negli anni '70 ero il "programmatore di sistema" (sysadmin) per un sistema IBM 370 e il mio datore di lavoro era un membro del gruppo di utenti di IBM SHARE. A volte capita che qualcuno abbia inviato un APAR (bug report) su qualche comportamento imprevisto di qualche comando CMS, e IBM risponderà a NOTABUG: il comando fa ciò che è stato progettato per fare (e cosa dice la documentazione).

SHARE ha inventato un contatore: BAD - Broken As Designed. Penso che questo potrebbe applicarsi a questa implementazione di eguali per gli array.

Non c'è niente di sbagliato nell'implementazione di Object.equals. L'oggetto non ha membri di dati, quindi non c'è nulla da confrontare. Due "oggetti" sono uguali se e solo se sono, di fatto, lo stesso oggetto (internamente, lo stesso indirizzo e la stessa lunghezza).

Ma questa logica non si applica agli array. Gli array hanno dati e ci si aspetta un confronto (tramite equals) per confrontare i dati. Idealmente, come fa Arrays.deepEquals, ma almeno come fa Arrays.equals (confronto superficiale degli elementi).

Quindi il problema è che l'array (come oggetto incorporato) non sovrascrive Object.equals. String (come classe denominata) fa ignora Object.equals e fornisce il risultato che si aspetta.

Altre risposte fornite sono corrette: [...]. Equals ([....]) confronta semplicemente i puntatori e non i contenuti. Forse un giorno qualcuno lo correggerà. O forse no: quanti programmi esistenti si rompono se [...]. Equivale effettivamente confrontato gli elementi? Non molti, sospetto, ma più che zero.

+2

mi piace l'acronimo Broken.As.Designed – Chris

0
import java.util.Arrays; 
public class ArrayDemo { 
    public static void main(String[] args) { 
    // initiliazing three object arrays 
    Object[] arr1 = new Object[] { 1, 123 }; 
    Object[] arr2 = new Object[] { 1, 123, 22, 4 }; 
    Object[] arr3 = new Object[] { 1, 123 }; 

    // comparing arr1 and arr2 
    boolean retval=Arrays.equals(arr1, arr2); 
    System.out.println("arr1 and arr2 equal: " + retval); 
    System.out.println("arr1 and arr2 equal: " + arr1.equals(arr2)); 

    // comparing arr1 and arr3 
    boolean retval2=Arrays.equals(arr1, arr3); 
    System.out.println("arr1 and arr3 equal: " + retval2); 
    System.out.println("arr1 and arr2 equal: " + arr1.equals(arr3)); 

    } 
} 

Ecco l'output:

arr1 and arr2 equal: false 
    arr1 and arr2 equal: false 

    arr1 and arr3 equal: true 
    arr1 and arr3 equal: false 

Vedendo questo tipo di problema Io personalmente andare per Arrays.equals(array1, array2) secondo la vostra domanda per evitare confusione.

Problemi correlati