316

假设我创建了一个对象并将其添加到我的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()returntrue吗?

4

10 回答 10

357

ArrayListimplements列表接口。

如果您查看该方法的Javadoc,Listcontains您将看到它使用该equals()方法来评估两个对象是否相同。

于 2010-04-15T04:23:14.767 回答
55

我认为正确的实现应该是

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;
    }
}
于 2012-10-31T19:27:11.190 回答
14

ArrayList 使用类(您的情况下的 Thing 类)中实现的 equals 方法进行相等比较。

于 2010-04-15T03:47:04.647 回答
12

通常,您还应该在hashCode()每次覆盖时覆盖equals(),即使只是为了提高性能。HashCode()决定在进行比较时您的对象被分类到哪个“桶”中,因此任何两个equal()评估为 true 的对象都应该返回相同的hashCode value(). 我不记得默认行为hashCode()(如果它返回 0,那么您的代码应该可以工作但速度很慢,但如果它返回地址,那么您的代码将失败)。我确实记得有很多次我的代码失败了,因为我忘记了覆盖hashCode()。:)

于 2010-04-15T07:30:09.157 回答
7

它对对象使用 equals 方法。因此,除非 Thing 覆盖 equals 并使用存储在对象中的变量进行比较,否则它不会在contains()方法上返回 true。

于 2010-04-15T03:48:20.430 回答
6
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;
    }
}

现在它起作用了;)

于 2012-09-10T08:07:49.860 回答
6

只是想注意,当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;
    }
}
于 2013-11-21T12:06:45.257 回答
4

其他海报已经解决了有关 contains() 如何工作的问题。

您问题的一个同样重要的方面是如何正确实现equals()。这个问题的答案实际上取决于什么构成了这个特定类的对象相等。在您提供的示例中,如果您有两个 x=5 的不同对象,它们是否相等?这真的取决于你想要做什么。

如果您只对对象相等性感兴趣,那么.equals()(Object 提供的那个)的默认实现仅使用标识(即 this == other)。如果这就是你想要的,那么就不要在你的类上实现 equals() (让它从 Object 继承)。您编写的代码,虽然如果您要进行身份验证的话是正确的,但永远不会出现在真正的 b/c 类中,与使用默认的 Object.equals() 实现相比,它没有任何好处。

如果你刚开始接触这些东西,我强烈推荐 Joshua Bloch 的 Effective Java 书。这是一本很好的读物,涵盖了这类事情(以及当您尝试做的不仅仅是基于身份的比较时,如何正确实现 equals())

于 2010-04-15T05:55:06.610 回答
3

JavaDoc的快捷方式:

布尔 包含(对象o)

如果此列表包含指定元素,则返回 true。更正式地说,当且仅当此列表包含至少一个元素 e 使得(o==null ? e==null : o.equals(e))

于 2015-10-01T11:49:08.813 回答
2

record覆盖equals

你说:

具有完全相同的构造函数输入的另一个对象

……和……</p>

假设构造函数没有对输入做任何有趣的事情,并且存储在两个对象中的变量是相同的。

正如其他答案所解释的,您必须覆盖该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 = true


Bonus feature: A record can be declared locally, within a method. Or like a conventional class you can declare a record as a nested class, or as a separate class.

于 2021-05-02T23:37:44.307 回答