给定类Foo,这个绝对糟糕的hashCode()实现:
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
minus()
的结果是一个空列表。如果我将 hashCode() 实现切换到 return name.hashCode()
,断言就会通过。 无论使用哪种实现,contains()
等方法都可以按预期工作。
我的问题不是如何实现更好的hashCode(),而是为什么minus()
这样做。
文档中描述的减号行为:
创建一个列表,由第一个列表的元素减去给定集合中出现的元素组成。
assert [1, "a", true, true, false, 5.3] - [true, 5.3] == [1, "a", false]
删除第二个列表中的每个元素。 在您的情况下,从 [f1,f2] 中删除所有 f3,其中所有 f1,f2 都相同,因此列表为空。
更精细的细节在DefaultGroovyMethods.minus
中,然后在NumberAwareComperator
中使用hashCode
。 正如您已经发现的那样,有关于此的开放票证(https://jira.codehaus.org/browse/GROOVY-7158)。 所以在眼睛下面,hashCode
在那里使用,行为是完全一致的......应该在那里使用吗? 也许不是,因为在某些情况下,它真的变得奇怪(例如 [[x:0,y:0]]-[[x:1,y:1]]==[]
)。
案例[f1,f2]-f3
在代码中采用另一种路由,因此行为不同。
目前,我最好的猜测是,您将minus
用于不可变类型(如上例所示),其中效果很好。 除此之外,而是使用集合。
Java 集合使用 hashCode/equals
的实现来确定对象相等性。hashCode
的实现表明f1
、f2
和f3
都是"相同的"。粗略地说:
[f1, f2] - [f3]
可以理解为
从列表中删除所有与 f3 相同的对象
因此,它会删除所有对象。
您似乎已经意识到这是一种可怕的实现hashCode
的方式,因此实际上只是"垃圾输入,垃圾输出"的情况。