Java中的equals与Arrays.equals

equals vs Arrays.equals in Java

提问人:PandaConda 提问时间:1/8/2012 最后编辑:Laser InfinitePandaConda 更新时间:12/25/2022 访问量:212158

问:

在 Java 中比较数组时,以下 2 个语句之间有什么区别吗?

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

如果是这样,它们是什么?

Java 数组 相等

评论

0赞 Valerio Bozz 9/28/2023
我标记了一条要删除的评论,因为它是对话/答案,而不是关于改进当前问题。如果它被删除,请同时删除我的评论:)

答:

93赞 alf 1/8/2012 #1

这是一个臭名昭著的问题:因为数组被严重损坏,永远不要使用它。.equals()

也就是说,它不是“被破坏”的,就像“有人以一种非常错误的方式做了”——它只是在做定义的事情,而不是通常预期的。所以对于纯粹主义者来说:这完全没问题,这也意味着,永远不要使用它。

现在,预期的行为是比较数据。默认行为是比较身份,因为没有任何数据(对于纯粹主义者:是的,它有,但这不是重点);假设是,如果你需要在子类中,你将实现它。在数组中,没有适合您的实现,因此您不应该使用它。equalsObjectequals

所以区别在于,按照你所期望的方式工作(即比较内容),回退到实现,这反过来又比较了身份,因此最好用(对于纯粹主义者:是的,我知道)。Arrays.equals(array1, array2)array1.equals(array2)Object.equals==null

问题是,如果数组的元素没有正确实现,甚至会狠狠地咬你一口。我知道这是一个非常幼稚的说法,但有一个非常重要的不太明显的例子:考虑一个二维阵列。Arrays.equals(array1, array2)equals

Java 中的 2D 数组是数组的数组,而数组是损坏的(或者如果您愿意的话,则无用),因此在 2D 数组上不会像您预期的那样工作。equalsArrays.equals(array1, array2)

评论

16赞 Michael Borgwardt 1/8/2012
它没有损坏,它只是从 Object 继承而来的。
0赞 Martijn Courteaux 1/8/2012
数组是否具有 的自定义实现?我以为是没有被对象覆盖。equals()
0赞 alf 1/8/2012
@MichaelBorgwardt它是一个系统库,其方法不执行 javadoc 中所说的操作。对我来说,这听起来已经够破碎了。话虽如此,我承认这是一个非常有争议的说法,但我相信“它坏了”被更好地记住了,因此这样想要方便得多。
0赞 alf 1/8/2012
@MartijnCourteaux这正是问题所在:)
3赞 Kevin J. Chase 10/24/2016
对于数组的数组,您需要 Arrays.deepEquals---这是一直以来应该做的事情。(相关:Objects.deepEqualssomeArray.equals
341赞 Peter Lawrey 1/8/2012 #2

array1.equals(array2)与 相同,即它是同一个数组。正如@alf指出的那样,这不是大多数人所期望的。array1 == array2

Arrays.equals(array1, array2)比较数组的内容。


同样可能不是很有用,您需要使用 .array.toString()Arrays.toString(array)

评论

66赞 Adam Parkin 3/19/2013
请注意,对于多维数组,它不能按预期工作,它只比较第一维的项目是否引用相等。Apache commons 适用于多维数组。Arrays.equals()ArrayUtils.isEquals
7赞 Lake 10/29/2013
我惊呆了。是否有理由将array.equals实现为指针比较,而不是比较长度和每个对象?
2赞 Peter Lawrey 10/30/2013
@Lake确实比较了数组长度和包含的对象,但它没有做的是深入比较。事实上,equals 确实按预期工作,因为数组被破坏了,这首先不应该是一个问题。
53赞 Elliott Frisch 10/19/2014
@AdamParkin 这就是为什么我们有 Arrays.deepEquals(Object[], Object[])。
3赞 Peter Lawrey 8/1/2016
@JeewanthaSamaraweera这是该方法的定义,但是因为它不比较内容,这就是您需要该方法的原因。.equals
1赞 Michael Borgwardt 1/8/2012 #3

of 数组继承自 ,因此它不查看 arrray 的内容,它只认为每个数组都等于自身。equals()Object

这些方法确实比较了数组的内容。所有基元类型都有重载,对象的重载使用对象自己的方法。Arrays.equals()equals()

评论

2赞 AlanFoster 1/8/2012
你说“数组的内容”,这是否也意味着多维数组?
1赞 Michael Borgwardt 1/8/2012
@AlanFoster:没有。多维数组是数组的数组,这意味着它们将被调用方法 Arrays.equals(Object[], Object[]),它调用子数组的 equals() 方法
1赞 aleroot 1/8/2012 #4

这:Arrays.equals(array1, array2)

检查两个数组是否包含相同数量的元素,并且两个数组中所有对应的元素对都相等。

这:array1.equals(array2)

将该对象与另一个对象进行比较,仅当两个对象的引用相等时才返回 true,如Object.equals()

7赞 Adam Zalcman 1/8/2012 #5

数组继承自 因此,仅当将数组与数组本身进行比较时,才会返回 true。equals()Object

另一方面,比较数组的元素。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()。

评论

0赞 Jorgesys 9/21/2022
“Arrays.equals 比较数组的元素”?
20赞 Eng.Fouad 1/8/2012 #6

深入了解这两种方法的实现,深入了解它们:

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;
}
15赞 A. P. Damien 4/30/2016 #7

叹息。早在 70 年代,我是 IBM 370 系统的“系统程序员”(系统管理员),我的雇主是 IBM 用户组 SHARE 的成员。有时,有人就某些 CMS 命令的某些意外行为提交了 APAR(错误报告),IBM 会响应 NOTABUG:该命令执行它的设计目的(以及文档所说的)。

SHARE想出了一个反驳这个办法:BAD -- Broken As Designed。我认为这可能适用于数组的等值实现。

Object.equals 的实现没有错。对象没有数据成员,因此没有什么可比较的。当且仅当两个“对象”实际上是同一个对象(内部地址和长度相同)时,它们才相等。

但这种逻辑不适用于数组。数组有数据,你希望比较(通过等于)来比较数据。理想情况下,Arrays.deepEquals 的方式,但至少是 Arrays.equals 的方式(元素的浅层比较)。

所以问题是数组(作为内置对象)不会覆盖 Object.equals。String(作为命名类)覆盖 Object.equals 并给出您期望的结果。

给出的其他答案是正确的:[...]。equals([....]) 只是比较指针而不是内容。也许有一天有人会纠正这一点。或者也许不是:如果 [...]。等于实际上比较了元素?我怀疑不多,但不止零。

评论

6赞 F.S. 12/27/2016
我喜欢 Broken.As.Designed 的首字母缩略词
0赞 Tayyab 11/15/2017 #8
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赞 jiahao 12/6/2018
这似乎是正确的,但在数组上,元素的顺序也很重要。例如,如果有另一个数组 Object[] array4 = new Object[] { 123, 1 };使用 Arrays.equals(array3, array4),它将返回 false。
0赞 sanlolness 9/6/2022 #9

我认为 Objects.deepEquals(Obj1,Obj2) 是这里最好的统一解决方案,如果 Obj1 和 Obj2 是两个 int 数组,它将为您调用 Arrays.deepEquals0(a, b) 方法。如果不比较字符串,则只会使用“.equals”(“==”)传统方法,因此在比较字符串时也非常有用。

它将涵盖那些正常的用法,如黄油,无需记住何时使用 ().equals()、Arrays.equals、(String a).equals((String b)) 或其他任何用法。

此 Objects.deepEquals 操作的时间复杂度为 O(n)。

    public static boolean deepEquals(Object a, Object b) {
        if (a == b)
            return true;
        else if (a == null || b == null)
            return false;
        else
            return Arrays.deepEquals0(a, b);
    }

常见用法如下: 比较 int 数组,whooo:

int[] num1 = { 1, 2, 3, 4 };
int[] num2 = { 1, 2, 3, 4 };
System.out.println(Objects.deepEquals(num1, num2));

还可以对比2D阵列,所以很好:

int[][] nums1 = { { 1, 2 }, { 2, 3 }, { 3, 4 } };
int[][] nums2 = { { 1, 2 }, { 2, 3 }, { 3, 4 } };
System.out.println(Objects.deepEquals(nums1, nums2));

比较字符串,甚至更大:

String s1 = "sasfd!";
String s2 = "sasfd" + "!";
System.out.println(Objects.deepEquals(s1, s2));

我喜欢普遍适用的方法