LinkedHashSet:hashCode() 和 equals() 匹配,但 contains() 不匹配
以下怎么可能:
void contains(LinkedHashSet data, Object arg) {
System.out.println(data.getClass()); // java.util.LinkedHashSet
System.out.println(arg.hashCode() == data.iterator().next().hashCode()); // true
System.out.println(arg.equals(data.iterator().next())); // true
System.out.println(new ArrayList(data).contains(arg)); // true
System.out.println(new HashSet(data).contains(arg)); // true
System.out.println(new LinkedHashSet(data).contains(arg)); // true (!)
System.out.println(data.contains(arg)); // false
}
我做错了什么吗?
显然,它并不总是发生(如果您创建一组简单的对象,则不会重现它)。但在我的情况下,使用更复杂的 arg 类时,这种情况总是会发生。
编辑:我在这里不定义 arg
的主要原因是它是相当大的类,Eclipse 生成的 hashCode
跨越 20 行和等于
两倍长。我认为这无关紧要——只要它们对于两个对象来说是相等的。
How is the following possible:
void contains(LinkedHashSet data, Object arg) {
System.out.println(data.getClass()); // java.util.LinkedHashSet
System.out.println(arg.hashCode() == data.iterator().next().hashCode()); // true
System.out.println(arg.equals(data.iterator().next())); // true
System.out.println(new ArrayList(data).contains(arg)); // true
System.out.println(new HashSet(data).contains(arg)); // true
System.out.println(new LinkedHashSet(data).contains(arg)); // true (!)
System.out.println(data.contains(arg)); // false
}
Am I doing something wrong?
Obviously, it doesn't always happen (if you create a trivial set of Objects, you won't reproduce it). But it does always happen in my case with more complicated class of arg.
EDIT: The main reason why I don't define arg
here is that's it's fairly big class, with Eclipse-generated hashCode
that spans 20 lines and equals
twice as long. And I don't think it's relevant - as long as they're equal for the two objects.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
当您构建自己的对象并计划在集合中使用它们时,您应该始终重写以下方法:
equals 的默认实现检查对象是否指向同一个对象,而您可能希望重新定义它以检查内容。
在相当实用的情况下,Object 类定义的 hashCode 方法确实为不同的对象返回不同的整数。为了遵守规则,一个对象的 hashCode 等于另一个对象的 hashCode 应该相同,因此您还必须重新定义 hashCode。
编辑:我本来期待一个错误的
hashCode
或equals
实现,但自从你的回答以来,你透露你在修改密钥后添加到 HashSet 或 HashMap。当您将对象添加到哈希集合时,会计算其 hashCode 并将其映射到集合中的物理位置。
如果用于计算 hashCode 的某些字段发生变化,hashCode 本身也会发生变化,因此 HashSet 的实现将会变得混乱。当它尝试获取对象时,它将查看另一个物理位置,但不会找到该对象。如果您枚举该集合,该对象仍然会存在。
因此,请始终使 HashMap 或 HashSet 键不可变< /a>.
When you build your own objects, and plan to use them in a collection you should always override the following methods:
The default implementation of equals checks whether the objects point to the same object, while you'd probably want to redefine it to check the contents.
As much as is reasonably practical, the hashCode method defined by class Object does return distinct integers for distinct objects. To respect the rules an hashCode of an object equals to another one should be the same, thus you've also to redefine hashCode.
EDIT: I was expecting a faulty
hashCode
orequals
implementation, but since your answer, you revealed that you're mutating the keys after they are added to an HashSet or HashMap.When you add an Object to an hash collection, its hashCode is computed and used to map it to a physical location in the Collection.
If some fields used to compute the hashCode are changed, the hashCode itself will change, so the HashSet implementation will become confused. When it tries to get the Object it will look at another physical location, and won't find the Object. The Object will still be present if you enumerate the set though.
For this reason, always make HashMap or HashSet keys Immutable.
知道了。一旦你知道了,答案就显而易见了,你只能尴尬地脸红。
这足以可靠地重现它。
说明:切勿改变用于 hashCode() 的字段!
Got it. Once you know it, the answer is so obvious you can only blush in embarrassment.
That is enough to reliably reproduce it.
Explanation: Thou Shalt Never Mutate Fields Used For hashCode()!
你的问题似乎缺少一些东西。我做了一些猜测:
编辑:跟踪不断变化的问题!
除了第一个输出之外,我仍然得到“true”。请更具体地说明“arg”参数的类型。
There seems to be something missing from your question. I have made some guesses:
EDITED: To keep track of changing question!
I still get "true" for ALL but the first output. Please be more specific about the type of the "arg" parameter.