2015-01-14 44 views
2

鉴于类Foo这种果断差的hashCode()实现:为什么返回零的hashCode()会导致List.minus()返回空列表?

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(),则断言通过。无论是哪种实现,像这样的方法都可以按预期工作。

我的问题是不是如何实现一个更好的hashCode(),但为什么minus()表现这种方式。

回答

2

这将是完全在docs for minus描述的行为:

创建第一个列表的给定集合的元素的每次出现的元素减去两者组成的列表。

assert [1, "a", true, true, false, 5.3] - [true, 5.3] == [1, "a", false] 

您删除每一个元素,即在第二个列表。在你的情况下,从[f1,f2]中删除全部相同的f3,因此为空列表。

更精细的细节在DefaultGroovyMethods.minus,然后在NumberAwareComperator,它使用hashCode。就像你已经找到的那样,有关于这个(https://jira.codehaus.org/browse/GROOVY-7158)的公开门票。因此,在那里使用hashCode,行为是完全一致的......应该在那里使用它?也许不是,因为有些情况下,它真的很奇怪(例如[[x:0,y:0]]-[[x:1,y:1]]==[])。

案例[f1,f2]-f3在代码中采取另一种路线,因此行为有所不同。

现在我最好的猜测是,你使用minus为不可变类型(如上例),它工作得很好。除此之外,宁可使用集合。

+0

你打败了我。 :) +1 – dmahapatro

+2

虽然,如果我们只做'[f1,f2] - f3',就不会发生这种情况。 :) – dmahapatro

+0

在这种情况下,“equals()”是如何考虑的?我在equals/hashCode合约中的假设是,当对象符合equals()合约时,它们的hashCode必须相等。但是,具有相同散列码的对象不一定相等。 – mwersch

-1

java集合使用hashCode/equals的实现来确定对象相等。你的实施hashCode表明f1,f2f3都是“相同的”。宽泛地说:

[f1, f2] - [f3] 

可以被解读为

从名单中删除是一样的F3

所以它删除所有对象的所有对象。

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

相关问题