Czy porównując 2 tablice w Javie, występują jakieś różnice?
Object[] array1, array2;
array1.equals(array2);
Arrays.equals(array1, array2);
A jeśli tak, to czym one są?
Czy porównując 2 tablice w Javie, występują jakieś różnice?
Object[] array1, array2;
array1.equals(array2);
Arrays.equals(array1, array2);
A jeśli tak, to czym one są?
Odpowiedzi:
array1.equals(array2)
jest taki sam jak array1 == array2
, tj. czy jest to ta sama tablica. Jak zauważa @alf, większość ludzi tego nie oczekuje.
Arrays.equals(array1, array2)
porównuje zawartość tablic.
Podobnie array.toString()
może nie być bardzo przydatne i musisz go użyć Arrays.toString(array)
.
Arrays.equals()
nie działa zgodnie z oczekiwaniami dla tablic wielowymiarowych, porównuje jedynie elementy z pierwszego wymiaru dla równości odniesienia. Apache commons ArrayUtils.isEquals
współpracuje z tablicami wielowymiarowymi.
Arrays.deepEquals(Object[], Object[])
.
.equals
nie porównuje zawartości, dlatego właśnie potrzebujesz tej metody.
Jest to niesławny problem: .equals()
ponieważ tablice są mocno zepsute, po prostu nigdy ich nie używaj.
To powiedziawszy, nie jest „zepsute”, jak w „ktoś zrobił to naprawdę źle” - po prostu robi to, co zdefiniowano, a nie to, czego zwykle się oczekuje. Tak więc dla purystów: jest całkowicie w porządku, a to oznacza również, że nigdy go nie używaj.
Teraz oczekiwanym zachowaniem equals
jest porównywanie danych. Domyślnym zachowaniem jest porównywanie tożsamości, ponieważ Object
nie ma żadnych danych (dla purystów: tak, ale nie o to chodzi); założeniem jest, że jeśli potrzebujesz equals
w podklasach, zaimplementujesz to. W tablicach nie ma dla ciebie żadnej implementacji, więc nie powinieneś jej używać.
Różnica polega na tym, że Arrays.equals(array1, array2)
działa tak, jak można się spodziewać (tzn. Porównuje zawartość), array1.equals(array2)
wraca do Object.equals
implementacji, która z kolei porównuje tożsamość, a zatem lepiej zastępuje ją ==
(dla purystów: tak, wiem o tym null
).
Problem w tym, że nawet Arrays.equals(array1, array2)
cię ugryzie, jeśli elementy tablicy nie zostaną equals
poprawnie zaimplementowane . To bardzo naiwne stwierdzenie, wiem, ale istnieje bardzo ważny, mniej oczywisty przypadek: rozważ tablicę 2D.
Tablica 2D w Javie to tablica tablic, a tablice equals
są zepsute (lub bezużyteczne, jeśli wolisz), więc Arrays.equals(array1, array2)
nie będą działać tak, jak oczekujesz na tablicach 2D.
Mam nadzieję, że to pomaga.
equals()
? Myślałem, że nie zostało zastąpione przez Object.
Arrays.deepEquals
--- to właśnie someArray.equals
powinno być zrobione przez cały czas. (Powiązane Objects.deepEquals
Zajrzyj do implementacji dwóch metod, aby je głęboko zrozumieć:
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);
}
podczas:
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;
}
Westchnienie. W latach 70. byłem „programistą systemu” (sysadmin) dla systemu IBM 370, a mój pracodawca był członkiem grupy użytkowników IBM SHARE. Czasami zdarza się, że ktoś przedłożył raport APAR (raport o błędzie) dotyczący niektórych nieoczekiwanych zachowań niektórych poleceń CMS, a IBM zareaguje NOTABUG: polecenie wykonuje to, do czego zostało przeznaczone (i co mówi dokumentacja).
SHARE wymyślił coś przeciwnego: BAD - Broken As Designed. Myślę, że może to dotyczyć implementacji równości dla tablic.
Nie ma nic złego w implementacji Object.equals. Obiekt nie ma elementów danych, więc nie ma nic do porównania. Dwa „obiekty” są równe wtedy i tylko wtedy, gdy są w rzeczywistości tym samym obiektem (wewnętrznie ten sam adres i długość).
Ale ta logika nie dotyczy tablic. Tablice zawierają dane i oczekujesz porównania (poprzez równe), aby porównać dane. Najlepiej, jak robi to Arrays.deepEquals, ale przynajmniej tak, jak robi to Arrays.equals (płytkie porównanie elementów).
Problemem jest to, że tablica (jako obiekt wbudowany) nie zastępuje Object.equals. String (w nazwie klasy) robi override Object.equals i daje wynik można oczekiwać.
Inne podane odpowiedzi są poprawne: [...]. Równa się ([....]) po prostu porównuje wskaźniki, a nie zawartość. Może kiedyś ktoś to naprawi. A może nie: ile istniejących programów zepsułoby się, gdyby [...] równa się faktycznie porównać elementy? Podejrzewam, że niewiele, ale więcej niż zero.
Tablice dziedziczą equals()
od Object
a więc porównać tylko zwraca true jeśli porównać tablicę przeciwko sobie.
Z drugiej strony Arrays.equals
porównuje elementy tablic.
Ten fragment wyjaśnia różnicę:
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
Zobacz także Arrays.equals()
. Inna metoda statyczna może być także interesujące: Arrays.deepEquals()
.
Arrays.equals(array1, array2)
:
sprawdź, czy obie tablice zawierają tę samą liczbę elementów i czy wszystkie odpowiednie pary elementów w dwóch tablicach są równe.
array1.equals(array2)
:
porównaj obiekt z innym obiektem i zwróć wartość true tylko wtedy, gdy odwołanie do dwóch obiektów jest równe jak w Object.equals()
equals()
Tablic jest odziedziczony Object
, więc nie patrzeć na treść arrrays, to tylko uważa każda tablica równe sobie.
Te Arrays.equals()
metody nie porównać zawartość tablic. Istnieją przeciążenia dla wszystkich typów pierwotnych, a ten dla obiektów używa własnych equals()
metod obiektów .
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));
}
}
Oto wynik:
array1 and array2 equal: false
array1 and array2 equal: false
array1 and array3 equal: true
array1 and array3 equal: false
Widząc tego rodzaju problem, osobiście wybrałbym Arrays.equals(array1, array2)
według twojego pytania, aby uniknąć zamieszania.