【问题标题】:Is this a good hashCode method for a class with a list?对于带有列表的类,这是一个好的 hashCode 方法吗?
【发布时间】:2022-12-12 20:14:51
【问题描述】:

我有一个 Foo 类,它具有很好覆盖的 hashCodeequals 方法和定义明确的 compareTo 方法。

class Foo {
    
    @Override
    public int hashCode() {
        // Well-define hashCode method
    }

    @Override
    public boolean equals(Object other) {
        // Well-define equals method
    }

    public int compareTo(OtherClass other) {
        // Well-defined compareTo method
    }

}

然后我有另一个班级 MyClass 覆盖了 hashCodeequals 方法。

class MyClass {
    
    int myValue;
    List<Foo> myList;

    @Override
    public int hashCode() {
        // Is this a good hashCode method?
        myList.sort(Foo::compareTo);
        return Objects.hash(myValue, myList);
    }

    @Override
    public boolean equals(Object other) {
        if (other == null || other.getClass() != this.getClass())
            return false;

        MyClass otherMyClass = (MyClass) other;

        if (myValue != otherMyClass.myValue)
            return false;

        myList.sort(Foo::compareTo);
        otherMyClass.myList.sort(Foo::compareTo);

        return myList.equals(otherMyClass.myList);
    }

}

我知道如果两个对象相等,那么它们的哈希值也必须相等,而 MyClasshashCode 方法就是这样做的。但我不确定我的方法是否是一个好的哈希生成器。是吗?

PS:排序myList是个好主意,还是我应该使用排序后的副本进行比较? myList 的顺序与MyClass 无关。

【问题讨论】:

  • 我个人永远不会期望 hashcode 或 equals 方法来修改对象。所以我不认为在 hashcode 或 equals 方法中对列表进行排序是个好主意。如果您想确保列表中元素的顺序不影响 equals/hashcode 方法,您应该创建这些列表的副本并对副本进行排序,但保持原件不变。
  • @OHGODSPIDERS 说得通。谢谢!

标签: java oop hash hashcode


【解决方案1】:

为 提供的 hashCode 方法不是一个好的实现,因为它在计算哈希码之前对 List 字段进行排序。

通常,一个好的 hashCode 方法应该为两个相等的对象返回相同的值(根据 equals 方法),而不管其 List 字段中元素的顺序如何。在计算哈希码之前对列表进行排序违反了此要求,因为两个相等但具有不同顺序的列表字段的对象的哈希码将不同。

以下是如何以不依赖于 List 字段中元素顺序的方式实现 hashCode 方法的示例:

    public class MyClass {
    int myValue;
    List<Foo> myList;

    @Override
    public int hashCode() {
        return Objects.hash(myValue, myList);
    }

    @Override
    public boolean equals(Object other) {
        if (other == null || other.getClass() != this.getClass())
            return false;

        MyClass otherMyClass = (MyClass) other;

        if (myValue != otherMyClass.myValue)
            return false;

        return myList.equals(otherMyClass.myList);
    }
 }

【讨论】:

  • ChatGPT 是否提供了这个答案?我的方法不考虑 myList 的顺序。这就是我在比较之前对其进行排序的原因。这样,(2, 1, 2, 3) 和 (2, 1, 2, 3) 被认为是相等的,因为 (1, 2, 2, 3) 和 (1, 2, 2, 3) 是相等的。
  • 实际上,这个具体的答案是一个很好的例子,说明了为什么 ChatGPT 如此有问题:它以一种看起来非常合理的方式呈现了一个令人信服的明喻,这个答案肯定是错误的:如果你hashCodeequals 中对列表进行排序(并且不做任何其他事情来避免顺序依赖),然后是它们的结果将要取决于列表的初始顺序,这显然与 OP 要求的相反。
猜你喜欢
  • 1970-01-01
  • 2019-10-21
  • 2012-07-20
  • 1970-01-01
  • 2014-07-23
  • 2018-10-03
  • 1970-01-01
  • 1970-01-01
  • 2013-11-05
相关资源
最近更新 更多