Javaでのequals vs Arrays.equals


209

Javaで配列を比較するとき、次の2つのステートメントの間に違いはありますか?

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

もしそうなら、それらは何ですか?


java.util.Arrays.deepEquals(Object [] a1、Object [] a2)も
ご覧ください

回答:


299

array1.equals(array2)同じでありarray1 == array2、すなわちそれは同じ配列です。@alfが指摘するように、それはほとんどの人が期待するものではありません。

Arrays.equals(array1, array2) 配列の内容を比較します。


同様array.toString()に、あまり役に立たない可能性があるため、を使用する必要がありますArrays.toString(array)


59
Arrays.equals()多次元配列では期待どおりに機能しないことに注意してください。これは、1番目の次元のアイテムを比較するだけで、参照が等しいかどうかを確認します。Apache commons ArrayUtils.isEqualsは多次元配列で動作します。
アダムパーキン

4
びっくりした。長さとすべてのオブジェクトを比較するのではなく、array.equalsをポインター比較に実装する理由はありますか?

2
@Lake isは、配列の長さと含まれているオブジェクトを比較しますが、行わないのは詳細な比較です。等しいという事実は、配列の期待どおりに機能しませんが、これは最初から問題ではありません。
Peter Lawrey、2013年

48
@AdamParkinそれが私たちが持っている理由Arrays.deepEquals(Object[], Object[])です。
Elliott Frisch 2014年

3
@JeewanthaSamaraweeraはそのメソッドの定義ですが、.equalsコンテンツを比較しないため、そのメソッドが必要です。
Peter Lawrey、2016

86

これは悪名高い問題です。.equals()配列がひどく壊れているので、使用しないでください。

とはいえ、「誰かが本当に間違った方法でそれを行った」のように「壊れている」のではなく、定義されていることだけを行っており、通常予期されていることを行っているのではありません。だから純粋主義者にとっては、それは完全に素晴らしいことであり、それはまた、決してそれを使わないことを意味します。

の予想される動作equalsは、データを比較することです。Objectデータがないため、デフォルトの動作はアイデンティティを比較することです(純粋主義者の場合:はい、ありますが、それはポイントではありません)。前提は、equalsサブクラスで必要な場合は実装することです。配列には実装がないため、使用することはできません。

差があるので、Arrays.equals(array1, array2)働くあなたが期待するよう、(すなわち、コンテンツを比較して)array1.equals(array2)にフォールバックObject.equals順番にアイデンティティを比較し、ひいてはよりよいによって置き換えられている、実装==(純粋主義者のために:はい、私は知っていますnull)。

問題は、Arrays.equals(array1, array2)配列の要素がequals適切に実装されていない場合でも、一生懸命噛むことです。これは非常に単純なステートメントですが、2D配列を検討するという非常に重要な、それほど明白ではないケースがあります。

Javaの2D配列は配列の配列であり、配列equalsは壊れている(または必要に応じて役に立たない)ためArrays.equals(array1, array2)、2D配列では期待どおりに機能しません。

お役に立てば幸いです。


13
壊れていません。Objectから継承されているだけです。
Michael Borgwardt

配列にはカスタム実装がありequals()ますか?Objectからオーバーライドされなかったと思いました。
Martijn Courteaux 2012年

@MichaelBorgwardtこれはシステムライブラリであり、javadocで述べられていることを実行しないメソッドを備えています。私には十分に壊れた音。とは言っても、非常に議論の余地のある発言であることは認めますが、「壊れている」ことはよく覚えられているので、このように考える方がはるかに便利です。
ALF

@MartijnCourteauxそれはまさに問題です:)
alf

3
配列の配列については、あなたは必要ですArrays.deepEquals---それsomeArray.equalsはずっとやっていたはずのことです。(関連:Objects.deepEquals
Kevin J. Chase

16

2つのメソッドの実装を調べて、それらを深く理解します。

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

11

はぁ。70年代に戻ると、私はIBM 370システムの「システムプログラマ」(sysadmin)であり、雇用主はIBMユーザーグループSHAREのメンバーでした。一部のCMSコマンドの予期しない動作について誰かがAPAR(バグレポート)を送信したことが時々起こり、IBMはNOTABUGと応答します。コマンドは、設計されたとおりに(およびドキュメントに記載されているとおりに)実行します。

シェアはこれに対するカウンターを思いついた:悪い-設計どおりに壊れた。これは、配列の等価のこの実装に当てはまると思います。

Object.equalsの実装に問題はありません。オブジェクトにはデータメンバーがないため、比較するものはありません。2つの「オブジェクト」は、それらが実際には同じオブジェクト(内部的には同じアドレスと長さ)である場合に限り、等しくなります。

しかし、そのロジックは配列には適用されません。配列にはデータがあり、(equalsによる)比較でデータを比較する必要があります。理想的には、Arrays.deepEqualsが行う方法ですが、少なくともArrays.equalsが行う方法(要素の比較を浅くします)。

したがって、問題は、(組み込みオブジェクトとしての)配列がObject.equalsをオーバーライドしないことです。文字列(名前付きクラスとして) Object.equalsをオーバーライドし、期待どおりの結果を提供ます。

与えられた他の答えは正しいです:[...]。equals([....])は単に内容ではなくポインタを比較します。多分いつか誰かがこれを修正するでしょう。あるいは、そうでないかもしれません:[...]。equalsが実際に要素を比較すると、いくつの既存のプログラムが壊れますか?多くはないと思いますが、ゼロ以上です。


5
Broken.As.Designedの頭字語が好き
Chris

5

アレイは、継承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

Arrays.equals(array1, array2)

両方の配列に同じ数の要素が含まれているかどうか、および2つの配列内の対応するすべての要素のペアが等しいかどうかを確認します。

array1.equals(array2)

オブジェクトを別のオブジェクトと比較し、2つのオブジェクトの参照が Object.equals()


0

equals()アレイは、から継承されるObjectことがarrraysの内容を見ていないので、それは、各アレイは、それ自体に等しい考慮する。

Arrays.equals()方法はない配列の内容を比較します。すべてのプリミティブ型のオーバーロードがあり、オブジェクトのオーバーロードはオブジェクト独自のequals()メソッドを使用します。


2
あなたは「配列の内容」と言います、これは多次元配列も意味しますか?
AlanFoster 2012年

@AlanFoster:いいえ。多次元配列は配列の配列です。つまり、配列Arrays.equals(Object []、Object [])が呼び出され、サブ配列のequals()メソッドが呼び出されます
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));

   }
}

出力は次のとおりです。

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

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

この種の問題を見Arrays.equals(array1, array2)て、混乱を避けるためにあなたの質問に従って私は個人的に行きます。


正しいようですが、配列では要素の順序も重要です。たとえば、別の配列Object []がある場合、array4 = new Object [] {123、1}; Arrays.equals(array3、array4)では、falseを返します。
ジアハオ2018
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.