Groovy 为什么返回零的hashCode()会导致List.减号()返回空列表?
给定类Foo的hashCode()实现非常糟糕:Groovy 为什么返回零的hashCode()会导致List.减号()返回空列表?,groovy,hashcode,Groovy,Hashcode,给定类Foo的hashCode()实现非常糟糕: class Foo { String name public int hashCode() { 0 } public boolean equals(Object obj) { if (obj == null) { return false } if (!(obj instanceof Foo)) {
class Foo {
String name
public int hashCode() {
0
}
public boolean equals(Object obj) {
if (obj == null) {
return false
}
if (!(obj instanceof Foo)) {
return false
}
Foo foo = (Foo) obj
return this.name.equals(foo.name)
}
}
为什么下面的断言失败了
Foo f1 = new Foo(name: 'Name 1')
Foo f2 = new Foo(name: 'Name 2')
Foo f3 = new Foo(name: 'Name 2')
assert ([f1, f2] - [f3]).size() == 1
减号()的结果是一个空列表。如果我将hashCode()实现切换到return name.hashCode()
,断言就会通过。无论是哪种实现,像contains()
这样的方法都能按预期工作
我的问题不是如何实现更好的hashCode(),而是为什么减号()
会有这样的行为。这正是以下内容中描述的行为:
创建一个由第一个列表中的元素减去给定集合中每一个元素组成的列表
assert [1, "a", true, true, false, 5.3] - [true, 5.3] == [1, "a", false]
删除第二个列表中的每个元素。在您的例子中,从[f1,f2]中删除所有f3,其中所有f3都相同,因此为空列表
更精细的细节在中,然后在中,使用hashCode
。正如您已经发现的,有关于此()的公开票证。因此,在这里使用的是hashCode
,行为完全一致。。。应该在那里使用吗?也许不是,因为在某些情况下,它确实变得很奇怪(例如,[[x:0,y:0]]-[[x:1,y:1]]=[]
)
案例[f1,f2]-f3
在代码中采用另一条路径,因此行为不同
现在我最好的猜测是,对于不可变的类型(如上面的示例),使用减号,效果非常好。除此之外,更应该使用集合。java集合使用hashCode/equals的实现来确定对象相等性。对hashCode
的实现表明f1
、f2
和f3
都是“相同的”。粗略地说:
[f1, f2] - [f3]
可以理解为
从列表中删除与f3相同的所有对象
因此,它会删除所有对象
您似乎已经意识到,这是一种可怕的实现hashCode
的方法,所以这实际上只是一个“垃圾输入,垃圾输出”的例子+1尽管如此,如果我们只是执行[f1,f2]-f3
:,则不会发生这种情况在这种情况下,equals()
是如何考虑的?我在equals/hashCode契约中的假设是,当对象满足equals()
契约时,它们的hashCode必须相等。但是,具有相同hashCode的对象不一定相等,因为如果对象实现了Comparable
,则它只使用numberAwareCompare
。然后改为使用DefaultTypeTransformation.compareEqual(o1,o2)
,它逐渐依赖于对象本身的equals
方法。正是在这个时候。:)看起来像是识别了@cfrick在回答中提到的缺陷:NumberAwareComparator