uguale a Arrays.equals in Java


209

Quando si confrontano gli array in Java, ci sono differenze tra le seguenti 2 istruzioni?

Object[] array1, array2;
array1.equals(array2);
Arrays.equals(array1, array2);

E se sì, cosa sono?


Dai un'occhiata anche a java.util.Arrays.deepEquals (Object [] a1, Object [] a2)
ultraon

Risposte:


299

array1.equals(array2)è uguale a array1 == array2, ovvero è lo stesso array. Come sottolinea @alf, non è quello che la maggior parte delle persone si aspetta.

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


Allo stesso modo array.toString()potrebbe non essere molto utile e devi usarlo Arrays.toString(array).


59
Si noti che Arrays.equals()non funziona come previsto per gli array multidimensionali, ma confronta solo gli elementi della 1a dimensione per l'uguaglianza di riferimento. I comuni di Apache ArrayUtils.isEqualsfunzionano con array multidimensionali.
Adam Parkin,

4
Sono sbalordito. C'è un motivo per cui array.equals deve essere implementato per il confronto dei puntatori piuttosto che per confrontare la lunghezza e ogni oggetto?
Lago

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

48
@AdamParkin Ecco perché abbiamo Arrays.deepEquals(Object[], Object[]).
Elliott Frisch,

3
@JeewanthaSamaraweera è la definizione per quel metodo, tuttavia .equalsnon confronta i contenuti ed è per questo che hai bisogno di quel metodo.
Peter Lawrey,

86

È un problema famigerato: .equals()poiché gli array sono gravemente rotti, non usarli mai.

Detto questo, non è "rotto" come in "qualcuno lo ha fatto in modo davvero sbagliato" - sta solo facendo ciò che è definito e non ciò che di solito ci si aspetta. Quindi per i puristi: va benissimo, e questo significa anche non usarlo mai.

Ora il comportamento previsto per equalsè confrontare i dati. Il comportamento predefinito è di confrontare l'identità, in quanto Objectnon ha dati (per i puristi: sì, ma non è questo il punto); il presupposto è, se necessarioequals in sottoclassi, lo implementerai. Negli array, non c'è implementazione per te, quindi non dovresti usarlo.

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

Il problema è, anche Arrays.equals(array1, array2) ti morderà anche se gli elementi dell'array non vengono implementati equalscorrettamente. È un'affermazione molto ingenua, lo so, ma c'è un caso molto meno che ovvio: considerare un array 2D.

L'array 2D in Java è un array di array e equals sono rotti (o inutili se si preferisce), quindi Arrays.equals(array1, array2)non funzioneranno come previsto sugli array 2D.

Spero che aiuti.


13
Non è rotto, è solo ereditato da Object.
Michael Borgwardt,

Un array ha un'implementazione personalizzata per equals()? Pensavo che non fosse sovrascritto dall'oggetto.
Martijn Courteaux

@MichaelBorgwardt è una libreria di sistema, con un metodo che non fa ciò che viene detto nel javadoc. Mi sembra abbastanza rotto. Detto questo, ammetto che è un'affermazione molto discutibile, ma credo che "è rotto" sia ricordato meglio, e quindi è molto più conveniente pensarlo in questo modo.
alf

@MartijnCourteaux questo è esattamente il problema :)
alf

3
Per le matrici di matrici, è necessario Arrays.deepEquals--- è ciò che someArray.equalsavrebbe dovuto fare da sempre. (Relativo:. Objects.deepEquals)
Kevin J. Chase,

16

Guarda all'interno dell'implementazione dei due metodi per capirli profondamente:

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;
}

11

Sospiro. Negli anni '70 ero il "programmatore di sistema" (amministratore di sistema) per un sistema IBM 370 e il mio datore di lavoro era un membro del gruppo di utenti IBM SHARE. A volte capita che qualcuno abbia inviato un APAR (bug report) su alcuni comportamenti imprevisti di alcuni comandi CMS e IBM rispondesse a NOTABUG: il comando fa ciò per cui è stato progettato (e cosa dice la documentazione).

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

Non c'è niente di sbagliato nell'implementazione di Object.equals. L'oggetto non ha membri 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 alle matrici. Le matrici contengono dati e ci si aspetta che il confronto (tramite uguale) compari i dati. Idealmente, il modo in cui Arrays.deepEquals fa, ma almeno il modo in cui Arrays.equals fa (confronto superficiale degli elementi).

Quindi il problema è che l'array (come oggetto incorporato) non sovrascrive Object.equals. String (come una classe denominata) fa di override Object.equalsQ e dare il risultato che ci 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 spezzerebbero se [...] fosse effettivamente confrontato con gli elementi? Non molti, sospetto, ma più di zero.


5
Mi piace l'acronimo Broken.As.Designed
Chris del

5

Le matrici ereditano equals()daObject e quindi confrontare restituisce vero solo se si confrontano una matrice contro se stessa.

D'altro canto, Arrays.equals confronta gli elementi delle matrici.

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 ci possono essere interessanti: Arrays.deepEquals().


1

Il Arrays.equals(array1, array2) :

controlla se entrambi gli array contengono lo stesso numero di elementi e tutte le coppie corrispondenti di elementi nei due array sono uguali.

Il array1.equals(array2) :

confronta l'oggetto con un altro oggetto e restituisce vero solo se il riferimento dei due oggetti è uguale a quello di Object.equals()


0

L' equals()array of è ereditato da Object, quindi non guarda il contenuto degli array, ma considera ogni array uguale a se stesso.

I Arrays.equals()metodi non comparare i contenuti delle matrici. Ci sono sovraccarichi per tutti i tipi primitivi e quello per gli oggetti utilizza i equals()metodi propri degli oggetti .


2
dite "contenuto delle matrici", significa anche matrici multidimensionali?
AlanFoster

@AlanFoster: no. Le matrici multidimensionali sono matrici di matrici, il che significa che verranno invocati il ​​metodo Arrays.equals (Object [], Object []), che chiama i metodi equals () dei sotto-array
Michael Borgwardt,

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

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

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

   }
}

Ecco l'output:

    array1 and array2 equal: false
    array1 and array2 equal: false

    array1 and array3 equal: true
    array1 and array3 equal: false

Vedendo questo tipo di problema, vorrei personalmente seguire Arrays.equals(array1, array2)la tua domanda per evitare confusione.


Sembra essere corretto ma su array, anche l'ordine degli elementi è importante. Ad esempio, se esiste un altro array Object [] array4 = new Object [] {123, 1}; con Arrays.equals (array3, array4), restituirà false.
jiahao,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.