为什么 hashCode() return 零导致 List.minus() 到 return 一个空列表?

Why does a hashCode() returning zero cause List.minus() to return an empty list?

鉴于 class 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()会这样。

这正是 docs for minus:

中描述的行为

Create a List composed of the elements of the first list minus every occurrence of elements of the given Collection.

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

您删除了第二个列表中的每个元素。在您的情况下,从 [f1,f2] 中删除所有 f3,其中所有内容都相同,因此列表为空。

更详细的信息在 DefaultGroovyMethods.minus and then in NumberAwareComperator, which uses the hashCode. as you have already found, there are open tickets regarding this (https://jira.codehaus.org/browse/GROOVY-7158) 中。所以在眼皮底下,那里使用了 hashCode,行为是完全一致的……应该在那里使用吗?也许不是,因为在某些情况下,它真的很奇怪(例如 [[x:0,y:0]]-[[x:1,y:1]]==[])。

案例 [f1,f2]-f3 在代码中采用了另一条路线,因此行为不同。

现在我最好的猜测是,您将 minus 用于不可变类型(如上面的示例),它工作得很好。除此之外,更喜欢使用集合。

java 集合使用 hashCode/equals 的实现来确定对象相等性。您实施的 hashCode 表示 f1f2f3 都是 "the same"。松散地说:

[f1, f2] - [f3]

可以读作

Remove from the list all objects that are the same as f3

所以它删除了所有对象。

您似乎已经意识到这是实现 hashCode 的糟糕方式,因此它实际上只是 "garbage in, garbage out".

的一个例子