равняется Arrays.equals в Java - PullRequest
       48

равняется Arrays.equals в Java

196 голосов
/ 08 января 2012

При сравнении массивов в Java, есть ли различия между следующими двумя операторами?

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

И если да, то чем они являются?

Ответы [ 8 ]

282 голосов
/ 08 января 2012

array1.equals(array2) - это то же самое, что и array1 == array2, т. Е. Тот же массив. Как @alf указывает, что это не то, чего ожидает большинство людей.

Arrays.equals(array1, array2) сравнивает содержимое массивов.


Точно так же array.toString() может быть не очень полезным, и вам нужно использовать Arrays.toString(array).

80 голосов
/ 08 января 2012

Это печально известная проблема: .equals() для массивов сильно сломан, просто не используйте его, никогда.

Тем не менее, он не «сломан», как в «кто-то сделал это действительно неправильно» - он просто делает то, что определено, а не то, что обычно ожидается. Так что для пуристов: это совершенно нормально, и это также означает, что не используйте его, никогда.

Теперь ожидаемое поведение для equals заключается в сравнении данных. Поведение по умолчанию заключается в сравнении идентификаторов, поскольку Object не имеет никаких данных (для пуристов: да, есть, но это не главное); Предполагается, что если вам нужно equals в подклассах, вы реализуете его. В массивах для вас нет реализации, поэтому вы не должны ее использовать.

Таким образом, разница в том, что Arrays.equals(array1, array2) работает так, как вы ожидаете (т.е. сравнивает содержимое), array1.equals(array2) возвращается к реализации Object.equals, которая, в свою очередь, сравнивает идентичность и, следовательно, лучше заменяется на == (для пуристов: да, я знаю о null).

Проблема в том, что даже Arrays.equals(array1, array2) сильно укусит вас, если элементы массива не будут правильно реализовывать equals. Это очень наивное утверждение, я знаю, но есть очень важный, менее очевидный случай: рассмотрим двумерный массив.

2D-массив в Java - это массив массивов, и массивы equals разбиты (или бесполезны, если вы предпочитаете), поэтому Arrays.equals(array1, array2) не будет работать, как вы ожидаете, для 2D-массивов.

Надеюсь, это поможет.

16 голосов
/ 08 января 2012

Загляните внутрь реализации двух методов, чтобы глубже понять их:

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

while:

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;
}
10 голосов
/ 29 апреля 2016

Вздох. Еще в 70-х годах я был «системным программистом» (sysadmin) для системы IBM 370, а мой работодатель был членом группы пользователей IBM SHARE. Иногда может случиться, что кто-то представит APAR (отчет об ошибке) о непредвиденном поведении какой-либо команды CMS, и IBM ответит NOTABUG: команда выполняет то, для чего она предназначена (и что говорится в документации).

SHARE придумала счетчик: BAD - Broken As Designed. Я думаю, что это может относиться к этой реализации равных для массивов.

Нет ничего плохого в реализации Object.equals. Объект не имеет элементов данных, поэтому сравнивать не с чем. Два «Объекта» равны тогда и только тогда, когда они фактически являются одним и тем же Объектом (внутренне, с одинаковым адресом и длиной).

Но эта логика не относится к массивам. Массивы имеют данные, и вы ожидаете, что сравнение (через равно) сравнит данные. В идеале, способ Arrays.deepEquals, но, по крайней мере, способ Arrays.equals (поверхностное сравнение элементов).

Таким образом, проблема в том, что массив (как встроенный объект) не переопределяет Object.equals. String (как именованный класс) делает переопределением Object.equals и дает ожидаемый результат.

Другие ответы верны: [...]. Equals ([....]) просто сравнивает указатели, а не содержимое. Может быть, когда-нибудь кто-нибудь исправит это. Или, может быть, нет: сколько существующих программ сломалось бы, если бы [...]. Фактически сравнивал элементы? Не много, я подозреваю, но больше нуля.

5 голосов
/ 08 января 2012

Массивы наследуют equals() от Object и, следовательно, сравнение возвращает только true, если сравнивать массив с самим собой.

С другой стороны, Arrays.equals сравнивает элементы массивов.

Этот фрагмент объясняет разницу:

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

См. Также Arrays.equals(). Там может быть также интересен другой статический метод: Arrays.deepEquals().

1 голос
/ 08 января 2012

Arrays.equals(array1, array2):

проверить, содержат ли оба массива одинаковое количество элементов, и равны ли все соответствующие пары элементов в двух массивах.

array1.equals(array2):

сравнивает объект с другим объектом и возвращает истину, только если ссылка на два объекта равна, как в Object.equals()

0 голосов
/ 15 ноября 2017
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));

   }
}

Вот вывод:

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

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

Видя такую ​​проблему, я лично выбрал бы Arrays.equals(array1, array2) по вашему вопросу, чтобы избежать путаницы.

0 голосов
/ 08 января 2012

equals() массивов унаследовано от Object, поэтому он не смотрит на содержимое массивов, он только считает каждый массив равным самому себе.

Методы Arrays.equals() do сравнивают содержимое массивов. Для всех примитивных типов существуют перегрузки, а для объектов используются собственные методы equals() объектов.

...