代码之家  ›  专栏  ›  技术社区  ›  Maksim Dmitriev

如果我不想将对象用作哈希表中的键,为什么两个相等的对象会返回相等的哈希代码?

  •  1
  • Maksim Dmitriev  · 技术社区  · 9 年前

    这是Java文档 Object.hashCode() 说:

    如果根据equals(Object)方法,两个对象相等,则 对两个对象中的每一个调用hashCode方法必须产生 相同的整数结果。

    但他们没有解释 为什么? 两个相等的对象必须返回相等的哈希代码。为什么Oracle工程师决定 hashCode 重写时必须重写 equals ?

    等于 不调用 哈希代码 方法:

    @Override
    public boolean equals(Object arg0) {
        if (this == arg0) {
            return true;
        }
        if (!(arg0 instanceof MyClass)) {
            return false;
        }
        MyClass another = (MyClass) arg0;
        // compare significant fields here
    }
    

    在里面 有效的Java(第2版) 我读到:

    第9项:重写equals时始终重写hashCode。

    错误的一个常见来源是未能覆盖hashCode 方法必须在每个重写的类中重写hashCode 等于。否则将导致违反 对象的合同。hashCode,这将阻止您的类 与所有基于散列的集合一起正常工作, 包括HashMap、HashSet和Hashtable。

    假设我不需要使用 MyClass 作为哈希表的键。为什么我需要重写 hashCode() 在这种情况下?

    5 回复  |  直到 9 年前
        1
  •  4
  •   mszalbach    9 年前

    当然,当你有一个自己编写的小程序,并且每次使用一个不依赖的外部库时都要检查 hashCode() 那么您可以忽略所有这些警告。但当软件项目增长时,您将使用外部库,这些库将依赖于 hashCode() 而且你会浪费很多时间去寻找bug。或者在较新的Java版本中,一些其他类使用 hashCode() 你的程序也会失败。

    因此,实现这一点并遵循这一简单规则要容易得多,因为现代IDE可以自动生成 equals hashCode 只需单击一下。

    更新一个小故事 :在工作中,我们在很多类中也忽略了这个规则,只实现了最需要的一个 等于 compareTo 有一天发生了一些奇怪的事情,因为一个程序员在GUI中使用了Hash*类,而我们的对象没有遵循这个规则。最后,学徒需要搜索所有课程 等于 并且必须添加相应的 哈希代码 方法

        2
  •  3
  •   Sami Kuhmonen    9 年前

    正如文本所说,这违反了正在使用的通用合同。当然,如果你从未在任何地方使用过hashCode,那么没有人会强迫你实现它。

    但如果未来某一天需要它呢?如果该类被其他开发人员使用呢?这就是为什么有一个合同,这两个都必须执行,所以没有混淆。

        3
  •  2
  •   Joni    9 年前

    显然,如果没有人打电话给你班的 hashCode 方法,没有人会知道它与 equals 。您能保证在项目的持续时间内,包括维护期间,没有人需要从列表中删除重复的对象或将一些额外的数据与您的对象相关联吗?

    您可能只是更安全地实施 哈希代码 所以它与equals一致。这并不特别困难,总是返回0已经是一个有效的实现。

    (请不要只返回0)

        4
  •  1
  •   philipxy    9 年前

    原因 hashCode 必须被覆盖以同意 equals 是因为为什么和如何 哈希代码 使用。哈希代码被用作值的代替品,因此当将键值映射到某个对象时,可以使用哈希来提供具有合理空间的接近恒定的查找时间。当两个值比较相等(即,它们是相同的值)时,当用作哈希集合的键时,它们必须映射到相同的值。这就要求它们有相同的哈希码才能到达那里。

    你必须超越 哈希代码 因为手册中说你必须这样做。它说你必须这么做,因为做出的决定是,库可以假设你满足了这个约定,这样他们(你)就可以在使用你给它的值作为函数实现的关键时,获得哈希的性能优势。

        5
  •  -2
  •   Sharon Ben Asher    9 年前

    常见的魔法规定 // compare significant fields here 需要 equals() 也适用于 compareTo() (如果要对 MyClass )并且还用于使用哈希表。所以把这个逻辑放进去是有意义的 hashCode() 并让其他方法使用哈希码。