bằng với Arrays.equals trong Java


209

Khi so sánh các mảng trong Java, có sự khác biệt nào giữa 2 câu lệnh sau không?

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

Và nếu vậy, họ là gì?


Hãy xem java.util.Arrays.deepEquals (Object [] a1, Object [] a2)
ultraon

Câu trả lời:


299

array1.equals(array2)là giống như array1 == array2, tức là nó là cùng một mảng. Như @alf chỉ ra đó không phải là điều mà hầu hết mọi người mong đợi.

Arrays.equals(array1, array2) so sánh các nội dung của các mảng.


Tương tự array.toString()có thể không hữu ích lắm và bạn cần sử dụng Arrays.toString(array).


59
Lưu ý rằng Arrays.equals()không hoạt động như mong đợi cho các mảng nhiều chiều, nó chỉ so sánh các mục của chiều thứ 1 cho đẳng thức tham chiếu. Apache commons ArrayUtils.isEqualshoạt động với các mảng đa chiều.
Adam Parkin

4
Tôi sững sờ. Có một lý do cho mảng.equals được thực hiện để so sánh con trỏ hơn là so sánh độ dài và mọi đối tượng?
Hồ

2
@Lake không so sánh độ dài mảng và các đối tượng chứa, nhưng những gì nó không làm là so sánh sâu. Thực tế là công việc như mong đợi cho các mảng bị phá vỡ, điều này không phải là một vấn đề ở nơi đầu tiên.
Peter Lawrey

48
@AdamParkin Đó là lý do tại sao chúng ta có Arrays.deepEquals(Object[], Object[]).
Elliott Frisch

3
@JeewanthaSamaraweera là định nghĩa cho phương pháp đó, tuy nhiên đối với .equalsnó không so sánh nội dung đó là lý do tại sao bạn cần phương pháp đó.
Peter Lawrey

86

Đó là một vấn đề tai tiếng: .equals()đối với các mảng bị hỏng nặng, đừng bao giờ sử dụng nó.

Điều đó nói rằng, nó không "bị hỏng" như trong "ai đó đã làm điều đó một cách thực sự sai lầm" - đó chỉ là làm những gì được xác định và không như những gì thường mong đợi. Vì vậy, đối với những người theo chủ nghĩa thuần túy: nó hoàn toàn ổn, và điều đó cũng có nghĩa là, đừng bao giờ sử dụng nó.

Bây giờ hành vi dự kiến ​​cho equalslà để so sánh dữ liệu. Hành vi mặc định là so sánh danh tính, vì Objectkhông có bất kỳ dữ liệu nào (đối với những người theo chủ nghĩa thuần túy: có, nhưng đó không phải là vấn đề); giả định là, nếu bạn cần equalstrong các lớp con, bạn sẽ thực hiện nó. Trong mảng, không có triển khai nào cho bạn, vì vậy bạn không nên sử dụng nó.

Vì vậy, sự khác biệt là, Arrays.equals(array1, array2)hoạt động như bạn mong đợi (nghĩa là so sánh nội dung), array1.equals(array2)quay trở lại Object.equalsthực hiện, từ đó so sánh danh tính, và do đó tốt hơn được thay thế bằng ==(đối với những người theo chủ nghĩa thuần túy: có tôi biết về null).

Vấn đề là, thậm chí Arrays.equals(array1, array2)sẽ cắn bạn mạnh nếu các yếu tố của mảng không thực hiện equalsđúng. Đó là một tuyên bố rất ngây thơ, tôi biết, nhưng có một trường hợp rất ít quan trọng không rõ ràng: xem xét một mảng 2D.

Mảng 2D trong Java là một mảng các mảng và các mảng ' equalsbị hỏng (hoặc vô dụng nếu bạn thích), vì vậy Arrays.equals(array1, array2)sẽ không hoạt động như bạn mong đợi trên các mảng 2D.

Mong rằng sẽ giúp.


13
Nó không bị hỏng, nó chỉ được thừa hưởng từ Object.
Michael Borgwardt

Liệu một mảng có một thực hiện tùy chỉnh cho equals()? Tôi nghĩ rằng không bị ghi đè từ Object.
Martijn Courteaux

@MichaelBorgwardt đó là một thư viện hệ thống, với một phương thức không thực hiện được những gì đã nói trong javadoc. Âm thanh đủ phá vỡ với tôi. Điều đó nói rằng, tôi thừa nhận đó là một tuyên bố rất có thể tranh cãi, nhưng tôi tin rằng "nó bị hỏng" được ghi nhớ tốt hơn, và do đó sẽ thuận tiện hơn nhiều khi nghĩ về nó theo cách này.
alf

@MartijnCourteaux chính xác là vấn đề :)
alf

3
Đối với các mảng của mảng, bạn cần Arrays.deepEquals--- đó là điều someArray.equalsnên làm tất cả cùng. (Liên quan : Objects.deepEquals.)
Kevin J. Chase

16

Nhìn vào bên trong việc thực hiện hai phương pháp để hiểu chúng sâu sắc:

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

trong khi:

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

Thở dài. Trở lại những năm 70, tôi là "lập trình viên hệ thống" (sysadmin) cho một hệ thống IBM 370 và chủ nhân của tôi là thành viên của nhóm người dùng IBM CHIA SẺ. Đôi khi, có thể ai đó đã gửi một APAR (báo cáo lỗi) về một số hành vi không mong muốn của một số lệnh CMS và IBM sẽ trả lời NOTABUG: lệnh thực hiện những gì nó được thiết kế để làm (và những gì tài liệu nói).

CHIA SẺ đã đưa ra một phản ứng với điều này: BAD - Broken As Thiết kế. Tôi nghĩ rằng điều này có thể áp dụng cho việc thực hiện bằng này cho các mảng.

Không có gì sai khi triển khai Object.equals. Đối tượng không có thành viên dữ liệu, vì vậy không có gì để so sánh. Hai "Đối tượng" bằng nhau khi và chỉ khi trên thực tế chúng là cùng một Đối tượng (bên trong, cùng một địa chỉ và độ dài).

Nhưng logic đó không áp dụng cho mảng. Mảng có dữ liệu và bạn mong muốn so sánh (thông qua bằng) để so sánh dữ liệu. Lý tưởng nhất là cách Arrays.deepEquals thực hiện, nhưng ít nhất là cách Arrays.equals thực hiện (so sánh nông của các yếu tố).

Vì vậy, vấn đề là mảng đó (như một đối tượng tích hợp) không ghi đè lên Object.equals. Chuỗi (như một lớp được đặt tên) sẽ ghi đè Object.equals và đưa ra kết quả mà bạn mong đợi.

Các câu trả lời khác được đưa ra là chính xác: [...]. Bằng ([....]) chỉ đơn giản là so sánh các con trỏ và không phải là nội dung. Có lẽ một ngày nào đó sẽ có người sửa nó. Hoặc có thể không: có bao nhiêu chương trình hiện tại sẽ phá vỡ nếu [...]. Bằng thực sự so sánh các yếu tố? Không nhiều, tôi nghi ngờ, nhưng nhiều hơn không.


5
Tôi thích từ viết tắt của Broken.As.Dignign
Chris

5

Mảng kế thừa equals()từ Objectvà do đó so sánh chỉ trả về true nếu so sánh một mảng với chính nó.

Mặt khác, Arrays.equalsso sánh các yếu tố của mảng.

Đoạn trích này làm sáng tỏ sự khác biệt:

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

Xem thêm Arrays.equals(). Một phương pháp tĩnh khác cũng có thể được quan tâm : Arrays.deepEquals().


1

các Arrays.equals(array1, array2):

kiểm tra xem cả hai mảng có chứa cùng một số phần tử không và tất cả các cặp phần tử tương ứng trong hai mảng có bằng nhau không.

các array1.equals(array2):

so sánh đối tượng với đối tượng khác và chỉ trả về true nếu tham chiếu của hai đối tượng bằng nhau như trong Object.equals()


0

Các equals()mảng được kế thừa từ Object, vì vậy nó không nhìn vào nội dung của các mảng, nó chỉ xem xét mỗi mảng bằng chính nó.

Các Arrays.equals()phương pháp làm so sánh nội dung của mảng. Có quá tải cho tất cả các kiểu nguyên thủy và kiểu cho các đối tượng sử dụng các equals()phương thức riêng của các đối tượng .


2
bạn nói "nội dung của mảng", điều này có nghĩa là mảng đa chiều không?
AlanFoster

@AlanFoster: không. Mảng đa chiều là mảng của mảng, có nghĩa là chúng phương thức Arrays.equals (Object [], Object []) sẽ được gọi, gọi các phương thức bằng () của mảng phụ
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));

   }
}

Đây là đầu ra:

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

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

Nhìn thấy loại vấn đề này, cá nhân tôi sẽ đi Arrays.equals(array1, array2)theo câu hỏi của bạn để tránh nhầm lẫn.


Nó có vẻ đúng nhưng trên mảng, thứ tự của các phần tử cũng rất quan trọng. Chẳng hạn, nếu bạn có một mảng Object [] Array4 = new Object [] {123, 1}; với Arrays.equals (mảng3, mảng4), nó sẽ trả về false.
jiahao
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.