【问题标题】:Is there any practical point overriding hashcode if the class is not used as a key in a hashmap?如果类不用作哈希图中的键,是否有任何实际点覆盖哈希码?
【发布时间】:2017-10-22 09:36:39
【问题描述】:

我最近一直在学习 hashCode 函数和 HashMaps,并尝试为自己的类创建自己的 hashCode 函数。从我所做的研究来看,从实际的角度来看,需要重写 hashCode 的唯一原因似乎是该类是否将用作 HashMap 中的键,或者 hashCode 函数是否在其他地方使用.我知道它是要覆盖的 equals 和 hashCode 合同的一部分,将来另一个用户可能想在 HashMap 中使用它,但为了理解起见,我想知道该类是否从未使用过作为关键,我还需要重写 hashCode 函数吗?

【问题讨论】:

    标签: java hashmap key hashcode


    【解决方案1】:

    无论何时实现equals,您都应该始终实现hashCode,因为即使您从未将您的对象放入HashMap,您也不知道您正在使用的库可能会做什么。库可以随意依赖您对象的hashCode 而无需告诉您。

    即使您只是让您的 IDE 自动生成 hashCode 和 equals,或者即使它只是

    public int hashCode() {
        raise RuntimeException("This type doesn't support hashCode (for now).");
    }
    

    您永远不应让您的 hashCode 与您的 equals 不一致。

    【讨论】:

      【解决方案2】:

      是的,如果您覆盖equals,您也应该始终覆盖hashCode,即使您不希望您的对象存储在HashMap 或HashSet 中。有几个原因。

      1. 您的对象可能不会存储在 HashMap 或 HashSet 今天,但六个月后,您可能会决定这样做,并且一切似乎都正常直到它们严重破裂。那时,你会对自己说“%$^^&%*& 我应该实现hashCode!”

      2. 您的对象可能被其他人使用,并且他们希望您实现hashCode。当他们将您的对象存储在 HashMap 中并且它不起作用时,他们会说“%$^^&%*& Aaron 应该已经实现 hashCode!”

      3. 您可能会将对象交给某个库,而您不知道的是,该库可能希望将您的对象存储在基于哈希的集合中。

      4. 如果您的对象曾经存储在容器对象中,即使该容器本身不是基于哈希的,容器的 hashCode 通常在逻辑上依赖于您对象的 @987654335 @。例如,请参阅Arrays.hashCode 或 Optional.hashCode。

      5. hashCode 有时用于短路相等检查。

      底线是hashCode/equals 合约的重点是每个人都依赖合约来正确执行。关于遵守合同的假设贯穿于整个大型系统,而不仅仅是基于哈希的集合。

      【讨论】:

      • #5 在基于散列的集合之外是真的吗?
      • @shmosel 我想我以前见过这种做法(在基于散列的集合之外),但我可能需要做很多挖掘才能找到一个例子。但是根据equals/hashCode合约是合法的,所以我认为很可能有人在某个地方做了。
      • @shmosel 啊,没多久。请参阅此equals() 方法。我不太了解这段代码的作用,但它看起来是正确的。它缓存 hashCode 值,并避免在 hashCode 不相等时进行昂贵的相等检查。
      • 这是一个检查自己的哈希码的类,所以它不直接并行OP的情况,equals()显然不依赖hashCode()。我知道可以在外部进行类似的短路;我只是想知道它是否会发生在现实世界中。
      • @AaronBarnard hashCode 的主要用途是 1) 通过基于哈希的集合; 2) 通过不一定基于散列的容器,但在计算自己的散列码时使用它; 3) 等号和类似情况的短路。与前两种相比,后一种情况非常罕见。如果你确定你的对象在这些情况下永远不会被使用,你可以跳过实现 hashCode。这不像 JVM 会神奇地调用 hashCode 或任何东西,如果不覆盖它会导致这种神奇的破坏。
      【解决方案3】:

      没有。但是请记住HashMap 中的键与HashSet 中的值相同,因此您也无法将该对象存储在HashSet 中(至少如果您打算将其用于内容相等)。

      【讨论】:

      • 这实际上并不完全正确。看我的回答。或者您也许应该详细说明“内容平等”的含义
      • 是的。如果你只需要引用相等,那么这不是问题,但是如果你想要内容相等,那么它就是。如果对您来说是一个新术语,请查找内容相等性与引用相等性。
      • 鉴于 OP 对 Java 来说似乎很新,我认为答案应该更准确。
      • 他似乎了解equals/hashCode合约。你只是在重复他在你的回答中已经知道的事情。另一方面,我对他的问题给出了答案,即“不”。
      • 这个词通常不是“价值平等”吗?
      【解决方案4】:

      如果您没有在 key 中使用对象或任何其他基于哈希的数据结构,您不需要覆盖 Object.JVM 的 hashcode 方法,我认为您是正确的。JVM 提供了 hashcode 的默认实现。

      【讨论】:

        【解决方案5】:

        总会有hashCode 的默认实现在内部使用身份哈希码。也就是说,该类可以在HashSet 中使用,甚至可以作为HashMap 中的键使用,但这不会非常有效或没有意义——在不实现equals 的情况下使用Set 毫无意义。

        要考虑的重要一点是equals 和hashCode 之间的合同。也就是说,如果您覆盖equals,则必须覆盖hashCode,以便它为两个相等的实例返回相同的值。你对equals 的实现。换句话说,以下规则必须始终成立:

        如果a.equals(b) == true 那么a.hashCode() == b.hashCode()

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2014-02-17
          • 2012-02-19
          • 2019-03-21
          • 2023-01-12
          • 2019-10-04
          • 1970-01-01
          • 1970-01-01
          • 2015-11-27
          相关资源
          最近更新 更多