Equals vs Arrays.equals в Java

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

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

И если да, то каковы они?

+196
источник поделиться
8 ответов

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

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


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

+282
источник

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

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

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

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

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

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

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

+80
источник
другие ответы

Связанные вопросы


Похожие вопросы

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

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

а

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;
}
+16
источник

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

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

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

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

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

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

+10
источник

Массивы наследуют 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().

+5
источник

Arrays.equals(array1, array2):

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

array1.equals(array2):

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

+1
источник

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

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

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

   }
}

Вот результат:

    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
источник

Посмотрите другие вопросы по меткам или Задайте вопрос