ArrayList 的 contains() 方法如何评估对象?

发布于 2024-08-28 18:32:31 字数 673 浏览 11 评论 0 原文

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

Say I create one object and add it to my ArrayList. If I then create another object with exactly the same constructor input, will the contains() method evaluate the two objects to be the same? Assume the constructor doesn't do anything funny with the input, and the variables stored in both objects are identical.

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

Is this how the class should be implemented to have contains() return true?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(10

感情洁癖 2024-09-04 18:32:32

ArrayList 使用类(您的案例 Thing 类)中实现的 equals 方法来进行 equals 比较。

The ArrayList uses the equals method implemented in the class (your case Thing class) to do the equals comparison.

一片旧的回忆 2024-09-04 18:32:32

一般来说,每次覆盖 equals() 时,您也应该覆盖 hashCode(),即使只是为了提高性能。 HashCode() 决定在进行比较时将对象排序到哪个“桶”,因此 equal() 计算结果为 true 的任何两个对象都应返回相同的 hashCode value()。我不记得 hashCode() 的默认行为(如果它返回 0,那么您的代码应该可以运行,但速度很慢,但如果它返回地址,那么您的代码将失败)。我确实记得有很多次我的代码失败,因为我忘记覆盖 hashCode() 。 :)

Generally you should also override hashCode() each time you override equals(), even if just for the performance boost. HashCode() decides which 'bucket' your object gets sorted into when doing a comparison, so any two objects which equal() evaluates to true should return the same hashCode value(). I cannot remember the default behavior of hashCode() (if it returns 0 then your code should work but slowly, but if it returns the address then your code will fail). I do remember a bunch of times when my code failed because I forgot to override hashCode() though. :)

绝不服输 2024-09-04 18:32:32

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

It uses the equals method on the objects. So unless Thing overrides equals and uses the variables stored in the objects for comparison, it will not return true on the contains() method.

峩卟喜欢 2024-09-04 18:32:32
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;
    }
}

现在可以了;)

class Thing {  
    public int value;  

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

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

You must write:

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

Now it works ;)

风月客 2024-09-04 18:32:32

只是想注意,当 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;
    }
}

Just wanted to note that the following implementation is wrong when value is not a primitive type:

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

In that case I propose the following:

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;
    }
}
昨迟人 2024-09-04 18:32:32

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

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

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

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

Other posters have addressed the question about how contains() works.

An equally important aspect of your question is how to properly implement equals(). And the answer to this is really dependent on what constitutes object equality for this particular class. In the example you provided, if you have two different objects that both have x=5, are they equal? It really depends on what you are trying to do.

If you are only interested in object equality, then the default implementation of .equals() (the one provided by Object) uses identity only (i.e. this == other). If that's what you want, then just don't implement equals() on your class (let it inherit from Object). The code you wrote, while kind of correct if you are going for identity, would never appear in a real class b/c it provides no benefit over using the default Object.equals() implementation.

If you are just getting started with this stuff, I strongly recommend the Effective Java book by Joshua Bloch. It's a great read, and covers this sort of thing (plus how to correctly implement equals() when you are trying to do more than identity based comparisons)

看透却不说透 2024-09-04 18:32:32

JavaDoc 的快捷方式:

boolean contains(Object o)

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

Shortcut from JavaDoc:

boolean contains(Object o)

Returns true if this list contains the specified element. More formally,
returns true if and only if this list contains at least one element e such
that (o==null ? e==null : o.equals(e))

豆芽 2024-09-04 18:32:32

record 覆盖 equals

你说:

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

……并且……

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

正如其他答案所解释的,您必须覆盖 Object#equals 方法/16/docs/api/java.base/java/util/List.html#contains(java.lang.Object)" rel="nofollow noreferrer">List#contains 到工作。

Java 16+ 中,记录 功能会自动为您覆盖该方法。

记录是编写类的一种简单方式,其主要目的是透明且不可变地通信数据。默认情况下,您只需声明成员字段即可。编译器隐式创建构造函数、getters、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 );

运行时。

foundX = true


附加功能:可以在方法内本地声明记录。或者像传统的类一样,您可以将记录声明为嵌套类或单独的类。

record overrides equals

You said:

another object with exactly the same constructor input

… and …

Assume the constructor doesn't do anything funny with the input, and the variables stored in both objects are identical.

As other Answers explain, you must override the Object#equals method for List#contains to work.

In Java 16+, the record feature automatically overrides that method for you.

A record is a brief way to write a class whose main purpose is to communicate data transparently and immutably. By default, you simply declare the member fields. The compiler implicitly creates the constructor, getters, equals & hashCode, and toString.

The logic of equals by default is to compare each and every member field of one object to the counterpart in another object of the same class. Likewise, the default implementations of hashCode and toString methods also consider each and every member field.

record Thing( int amount ) {} ;

That’s it, that is all the code you need for a fully-functioning read-only class with none of the usual boilerplate code.

Example usage.

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

When run.

parity = true

Back to your List#contains question.

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

boolean foundX = things.contains( x );

When run.

foundX = 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.

空袭的梦i 2024-09-04 18:32:31

ArrayList实现列表接口。

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

ArrayList implements the List Interface.

If you look at the Javadoc for List at the contains method you will see that it uses the equals() method to evaluate if two objects are the same.

傲鸠 2024-09-04 18:32:31

我认为正确的实施应该是

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

I think that right implementations should be

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;
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文