sama dengan vs Arrays.equals di Jawa

209

Saat membandingkan array di Jawa, apakah ada perbedaan antara 2 pernyataan berikut?

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

Dan jika demikian, apakah mereka?

PandaConda
sumber
Lihatlah juga java.util.Arrays.deepEquals (Object [] a1, Object [] a2)
ultraon

Jawaban:

299

array1.equals(array2)sama dengan array1 == array2, yaitu apakah array yang sama. Seperti ditunjukkan @alf, bukan itu yang diharapkan kebanyakan orang.

Arrays.equals(array1, array2) membandingkan isi dari array.


Demikian pula array.toString()mungkin tidak terlalu berguna dan perlu Anda gunakan Arrays.toString(array).

Peter Lawrey
sumber
59
Catatan yang Arrays.equals()tidak berfungsi seperti yang diharapkan untuk array multidimensi, itu hanya membandingkan item dari dimensi 1 untuk persamaan referensi. Apache commons ArrayUtils.isEqualsbekerja dengan array multidimensi.
Adam Parkin
4
Saya terpana. Apakah ada alasan untuk array.equals diimplementasikan untuk perbandingan pointer daripada membandingkan panjang dan setiap objek?
Danau
2
@Lake is tidak membandingkan panjang array dan objek yang terkandung, tetapi apa yang tidak dilakukannya adalah perbandingan yang mendalam. Faktanya sama tidak bekerja seperti yang diharapkan untuk array rusak, ini seharusnya tidak menjadi masalah di tempat pertama.
Peter Lawrey
48
@AdamParkin Itu sebabnya kami punya Arrays.deepEquals(Object[], Object[]).
Elliott Frisch
3
@JeewanthaSamaraweera itu adalah definisi untuk metode itu, namun untuk .equalsitu tidak membandingkan konten yang mengapa Anda memerlukan metode itu.
Peter Lawrey
86

Ini masalah yang terkenal: .equals()karena array rusak parah, tapi jangan pernah menggunakannya.

Yang mengatakan, itu tidak "rusak" seperti pada "seseorang telah melakukannya dengan cara yang benar-benar salah" - itu hanya melakukan apa yang didefinisikan dan bukan apa yang biasanya diharapkan. Jadi untuk para puritan: tidak apa-apa, dan itu juga berarti, jangan pernah menggunakannya.

Sekarang perilaku yang diharapkan equalsadalah membandingkan data. Perilaku default adalah membandingkan identitas, karena Objecttidak memiliki data (untuk puritan: ya, tapi bukan itu intinya); Asumsinya adalah, jika Anda perluequals dalam subkelas, Anda akan menerapkannya. Dalam array, tidak ada implementasi untuk Anda, jadi Anda tidak seharusnya menggunakannya.

Jadi perbedaannya adalah, Arrays.equals(array1, array2)berfungsi seperti yang Anda harapkan (yaitu membandingkan konten), array1.equals(array2)kembali ke Object.equalsimplementasi, yang pada gilirannya membandingkan identitas, dan dengan demikian lebih baik digantikan oleh ==(untuk pembuat puritan: ya saya tahu tentang null).

Masalahnya, bahkan Arrays.equals(array1, array2)akan menggigit Anda dengan keras jika elemen array tidak diimplementasikan equalsdengan benar. Itu adalah pernyataan yang sangat naif, saya tahu, tetapi ada kasus yang sangat kurang penting: pertimbangkan array 2D.

Array 2D di Java adalah array array, dan array equalsrusak (atau tidak berguna jika Anda mau), jadi Arrays.equals(array1, array2)tidak akan berfungsi seperti yang Anda harapkan pada array 2D.

Semoga itu bisa membantu.

alf
sumber
13
Itu tidak rusak, itu hanya diwarisi dari Object.
Michael Borgwardt
Apakah array memiliki implementasi kustom equals()? Saya pikir tidak diganti dari Object.
Martijn Courteaux
@MichaelBorgwardt itu adalah perpustakaan sistem, dengan metode yang tidak melakukan apa yang dikatakan di javadoc. Kedengarannya cukup rusak bagiku. Yang mengatakan, saya akui itu adalah pernyataan yang sangat bisa diperdebatkan, tetapi saya percaya bahwa "itu rusak" diingat lebih baik, dan dengan demikian jauh lebih mudah untuk memikirkannya dengan cara ini.
alf
@ MartijnCourteaux itulah masalahnya :)
alf
3
Untuk array array, Anda perlu Arrays.deepEquals--- itulah yang someArray.equalsseharusnya dilakukan selama ini. (Terkait:. Objects.deepEquals)
Kevin J. Chase
16

Lihat ke dalam implementasi dua metode untuk memahami mereka secara mendalam:

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

sementara:

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;
}
Eng.Fouad
sumber
11

Mendesah. Kembali di 70-an saya adalah "programmer sistem" (sysadmin) untuk sistem IBM 370, dan majikan saya adalah anggota kelompok pengguna IBM SHARE. Kadang-kadang akan terjadi bahwa seseorang menyerahkan APAR (laporan bug) pada beberapa perilaku tak terduga dari beberapa perintah CMS, dan IBM akan menanggapi NOTABUG: perintah melakukan apa yang dirancang untuk dilakukan (dan apa yang dikatakan dokumentasi).

SHARE datang dengan penghitung untuk ini: BAD - Broken Asesign. Saya pikir ini mungkin berlaku untuk implementasi equals for array ini.

Tidak ada yang salah dengan implementasi Object.equals. Objek tidak memiliki data anggota, jadi tidak ada yang bisa dibandingkan. Dua "Objek" adalah sama jika dan hanya jika mereka, pada kenyataannya, adalah Obyek yang sama (secara internal, alamat dan panjang yang sama).

Tetapi logika itu tidak berlaku untuk array. Array memiliki data, dan Anda mengharapkan perbandingan (melalui sama dengan) untuk membandingkan data. Idealnya, cara Array.deepEquals lakukan, tapi setidaknya cara Array.equals lakukan (perbandingan elemen yang dangkal).

Jadi masalahnya adalah array (sebagai objek bawaan) tidak menimpa Object.equals. String (sebagai kelas bernama) tidak menimpa Object.equals dan memberikan hasil yang Anda harapkan.

Jawaban lain yang diberikan adalah benar: [...]. Equals ([....]) cukup membandingkan pointer dan bukan isinya. Mungkin suatu hari seseorang akan memperbaiki ini. Atau mungkin tidak: berapa banyak program yang ada akan rusak jika [...] sama dengan benar-benar membandingkan elemen? Tidak banyak, saya kira, tetapi lebih dari nol.

AP Damien
sumber
5
Saya suka singkatan Broken.As.Designed
Chris
5

Array mewarisi equals()dari Objectdan karenanya membandingkan hanya mengembalikan true jika membandingkan array terhadap dirinya sendiri.

Di sisi lain, Arrays.equalsbandingkan elemen dari array.

Cuplikan ini menjelaskan perbedaannya:

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

Lihat juga Arrays.equals(). Metode lain statis ada juga mungkin menarik: Arrays.deepEquals().

Adam Zalcman
sumber
1

The Arrays.equals(array1, array2):

periksa apakah kedua array berisi jumlah elemen yang sama, dan semua pasangan elemen yang sesuai dalam kedua array sama.

The array1.equals(array2):

membandingkan objek ke objek lain dan mengembalikan true hanya jika referensi kedua objek sama seperti di Object.equals()

aleroot
sumber
0

The equals()array diwariskan dari Object, sehingga tidak melihat isi dari arrrays, hanya menganggap setiap array sama untuk dirinya sendiri.

The Arrays.equals()metode yang membandingkan isi array. Ada kelebihan untuk semua tipe primitif, dan satu untuk objek menggunakan metode objek sendiri equals().

Michael Borgwardt
sumber
2
Anda mengatakan "isi array", apakah ini berarti array multidimensi juga?
AlanFoster
@AlanFoster: tidak. Array multidimensi adalah array array, yang berarti mereka memilah Array.equals (Object [], Object []) akan dipanggil, yang memanggil metode equals () equals sub-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));

   }
}

Berikut hasilnya:

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

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

Melihat masalah seperti ini saya pribadi akan mencari Arrays.equals(array1, array2)sesuai pertanyaan Anda untuk menghindari kebingungan.

Tayyab
sumber
Tampaknya benar tetapi pada array, urutan elemen juga penting. Misalnya, jika Anda ada Objek array lain [] array4 = Objek baru [] {123, 1}; dengan Arrays.equals (array3, array4), itu akan mengembalikan false.
jiahao