簡體   English   中英

ArrayList 的 contains() 方法如何評估對象?

[英]How does a ArrayList's contains() method evaluate objects?

假設我創建了一個對象並將其添加到我的ArrayList 如果我然后創建另一個具有完全相同的構造函數輸入的對象, contains()方法會評估這兩個對象是否相同嗎? 假設構造函數沒有對輸入做任何有趣的事情,並且存儲在兩個對象中的變量是相同的。

ArrayList<Thing> basket = new ArrayList<Thing>();  
Thing thing = new Thing(100);  
basket.add(thing);  
Thing another = new Thing(100);  
basket.contains(another); // true or false?

class Thing {  
    public int value;  

    public Thing (int x) {
        value = x;
    }

    equals (Thing x) {
        if (x.value == value) return true;
        return false;
    }
}

這是應該如何實現class以使contains()返回true

ArrayList implements了 List 接口。

如果您在contains方法中查看ListJavadoc,您將看到它使用equals()方法來評估兩個對象是否相同。

我認為正確的實現應該是

public class Thing
{
    public int value;  

    public Thing (int x)
    {
        this.value = x;
    }

    @Override
    public boolean equals(Object object)
    {
        boolean sameSame = false;

        if (object != null && object instanceof Thing)
        {
            sameSame = this.value == ((Thing) object).value;
        }

        return sameSame;
    }
}

ArrayList 使用在類(您的案例 Thing 類)中實現的 equals 方法進行 equals 比較。

通常,您也應該在每次覆蓋equals()時覆蓋hashCode() equals() ,即使只是為了提高性能。 HashCode()決定在進行比較時您的對象被分類到哪個“桶”中,因此equal()評估為 true 的任何兩個對象都應返回相同的hashCode value() 我不記得hashCode()的默認行為(如果它返回 0,那么您的代碼應該可以運行但速度很慢,但是如果它返回地址,那么您的代碼將失敗)。 我確實記得有很多次我的代碼失敗了,因為我忘記覆蓋hashCode() :)

它在對象上使用 equals 方法。 因此,除非 Thing 覆蓋 equals 並使用存儲在對象中的變量進行比較,否則它不會在contains()方法上返回 true。

class Thing {  
    public int value;  

    public Thing (int x) {
        value = x;
    }

    equals (Thing x) {
        if (x.value == value) return true;
        return false;
    }
}

你必須寫:

class Thing {  
    public int value;  

    public Thing (int x) {
        value = x;
    }

    public boolean equals (Object o) {
    Thing x = (Thing) o;
        if (x.value == value) return true;
        return false;
    }
}

現在它起作用了;)

只是想注意,當value不是原始類型時,以下實現是錯誤的:

public class Thing
{
    public Object value;  

    public Thing (Object x)
    {
        this.value = x;
    }

    @Override
    public boolean equals(Object object)
    {
        boolean sameSame = false;

        if (object != null && object instanceof Thing)
        {
            sameSame = this.value == ((Thing) object).value;
        }

        return sameSame;
    }
}

在這種情況下,我提出以下建議:

public class Thing {
    public Object value;  

    public Thing (Object x) {
        value = x;
    }

    @Override
    public boolean equals(Object object) {

        if (object != null && object instanceof Thing) {
            Thing thing = (Thing) object;
            if (value == null) {
                return (thing.value == null);
            }
            else {
                return value.equals(thing.value);
            }
        }

        return false;
    }
}

其他海報已經解決了關於 contains() 如何工作的問題。

您問題的一個同樣重要的方面是如何正確實現 equals()。 對此的答案實際上取決於構成該特定類的對象相等性的內容。 在您提供的示例中,如果您有兩個不同的對象,它們的 x=5,它們是否相等? 這真的取決於你想要做什么。

如果您只對對象相等性感興趣,那么 .equals() 的默認實現(Object 提供的實現)僅使用標識(即 this == other)。 如果這就是你想要的,那么就不要在你的類上實現 equals() (讓它從 Object 繼承)。 您編寫的代碼雖然有點正確,但如果您要進行標識,則永遠不會出現在真正的 b/c 類中,與使用默認的 Object.equals() 實現相比,它沒有任何好處。

如果你剛開始接觸這些東西,我強烈推薦 Joshua Bloch 的 Effective Java 一書。 這是一本很好的讀物,涵蓋了這類事情(以及當您嘗試做的不僅僅是基於身份的比較時如何正確實現 equals())

JavaDoc 的快捷方式:

布爾值包含(對象 o)

如果此列表包含指定的元素,則返回 true。 更正式地說,當且僅當此列表包含至少一個元素 e 使得(o==null ? e==null : o.equals(e))時才返回 true

record覆蓋equals

你說:

另一個具有完全相同構造函數輸入的對象

… 和 …

假設構造函數沒有對輸入做任何有趣的事情,並且存儲在兩個對象中的變量是相同的。

正如其他答案所解釋的那樣,您必須覆蓋Object#equals方法才能使List#contains工作。

Java 16+ 中記錄功能會自動為您覆蓋該方法。

記錄是編寫類的一種簡短方式,其主要目的是透明和不可變地通信數據。 默認情況下,您只需聲明成員字段。 編譯器隱式地創建構造函數、getter、 equals & hashCodetoString

默認情況下, equals的邏輯是將一個對象的每個成員字段與同一類的另一個對象中的對應成員字段進行比較。 同樣, hashCodetoString方法的默認實現也會考慮每個成員字段。

record Thing( int amount ) {} ;

就是這樣,這是一個功能齊全的只讀類所需的所有代碼,沒有任何通常的樣板代碼

示例用法。

Thing x = new Thing( 100 ) ; 
Thing y = new Thing( 100 ) ; 
boolean parity = x.equals( y ) ;

跑的時候。

奇偶校驗 = 真

回到你的List#contains問題。

Thing x = new Thing( 100 );
List < Thing > things =
        List.of(
                new Thing( 100 ) ,
                new Thing( 200 ) ,
                new Thing( 300 )
        );

boolean foundX = things.contains( x );

跑的時候。

發現 X = 真


額外功能:可以在方法中本地聲明記錄。 或者像傳統類一樣,您可以將記錄聲明為嵌套類或單獨的類。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM