为什么hashCode()返回零会导致List.minus()返回一个空列表?

时间:2015-01-14 16:40:59

标签: 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)) {
            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()会以这种方式运行。

2 个答案:

答案 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的实施表明f1f2f3都“相同”。松散地说:

[f1, f2] - [f3]

可以理解为

  

从列表中删除与f3

相同的所有对象

所以删除所有对象。

您似乎已经意识到这是实现hashCode的一种可怕方式,所以它实际上只是“垃圾进入,垃​​圾出局”的情况。