ArrayList 的 contains() 方法如何评估对象?
假设我创建一个对象并将其添加到我的 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
吗?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(10)
ArrayList 使用类(您的案例 Thing 类)中实现的 equals 方法来进行 equals 比较。
The ArrayList uses the equals method implemented in the class (your case Thing class) to do the equals comparison.
一般来说,每次覆盖
equals()
时,您也应该覆盖hashCode()
,即使只是为了提高性能。HashCode()
决定在进行比较时将对象排序到哪个“桶”,因此equal()
计算结果为 true 的任何两个对象都应返回相同的hashCode
value()
。我不记得hashCode()
的默认行为(如果它返回 0,那么您的代码应该可以运行,但速度很慢,但如果它返回地址,那么您的代码将失败)。我确实记得有很多次我的代码失败,因为我忘记覆盖hashCode()
。 :)Generally you should also override
hashCode()
each time you overrideequals()
, even if just for the performance boost.HashCode()
decides which 'bucket' your object gets sorted into when doing a comparison, so any two objects whichequal()
evaluates to true should return the samehashCode
value()
. I cannot remember the default behavior ofhashCode()
(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 overridehashCode()
though. :)它对对象使用 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.你必须写:
现在可以了;)
You must write:
Now it works ;)
只是想注意,当
value
不是原始类型时,以下实现是错误的:在这种情况下,我提出以下建议:
Just wanted to note that the following implementation is wrong when
value
is not a primitive type:In that case I propose the following:
其他发帖者已经解决了有关 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)
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))
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
&hashCode
和toString
。默认情况下,
equals
的逻辑是将一个对象的每个成员字段与同一类的另一个对象中的对应成员字段进行比较。同样,hashCode
和toString
方法的默认实现也会考虑每个成员字段。就是这样,这就是一个功能齐全的只读类所需的所有代码,没有任何常见的 样板代码。
用法示例。
运行时。
回到您的
List#contains
问题。运行时。
附加功能:可以在方法内本地声明记录。或者像传统的类一样,您可以将记录声明为嵌套类或单独的类。
record
overridesequals
You said:
… and …
As other Answers explain, you must override the
Object#equals
method forList#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
, andtoString
.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 ofhashCode
andtoString
methods also consider each and every member field.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.
When run.
Back to your
List#contains
question.When run.
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.
ArrayList
实现
列表接口。如果您查看 Javadoc for
List
在contains
方法中,您将看到它使用equals()
方法来评估两个对象是否相同是一样的。ArrayList
implements
the List Interface.If you look at the Javadoc for
List
at thecontains
method you will see that it uses theequals()
method to evaluate if two objects are the same.我认为正确的实施应该是
I think that right implementations should be