给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()
会以这种方式运行。
答案 0 :(得分:2)
这正是docs for minus中描述的行为:
创建一个由第一个列表的元素组成的列表减去给定Collection的每个元素。
assert [1, "a", true, true, false, 5.3] - [true, 5.3] == [1, "a", false]
删除第二个列表中的每个元素。在你的情况下,从[f1,f2]删除所有f3,其中所有f3都是相同的,因此是空列表。
更精细的细节位于DefaultGroovyMethods.minus
,然后位于使用hashCode
的{{3}}。正如您已经发现的那样,有关于此的开放票(NumberAwareComperator
)。所以在眼睛下面,那里使用hashCode
,行为是完全一致的......它应该在那里使用吗?也许不是,因为有些情况下它真的很奇怪(例如[[x:0,y:0]]-[[x:1,y:1]]==[]
)。
案例[f1,f2]-f3
在代码中采用另一条路径,因此表现不同。
现在我最好的猜测是,你将minus
用于不可变类型(如上例所示),它可以很好地运行。除此之外,宁愿使用套装。
答案 1 :(得分:-1)
java Collections使用hashCode/equals
的实现来确定对象相等性。您对hashCode
的实施表明f1
,f2
和f3
都“相同”。松散地说:
[f1, f2] - [f3]
可以理解为
从列表中删除与f3
相同的所有对象
所以删除所有对象。
您似乎已经意识到这是实现hashCode
的一种可怕方式,所以它实际上只是“垃圾进入,垃圾出局”的情况。