如果 class 未用作哈希图中的键,是否有任何实际点可以覆盖哈希码?

Is there any practical point overriding hashcode if the class is not used as a key in a hashmap?

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

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

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

总会有 hashCode 的默认实现在内部使用身份哈希码。也就是说 class 可以在 HashSet 中使用,甚至可以作为 HashMap 中的键,但这不会非常有效或有意义 - 使用 [=13 没有意义=] 没有实施 equals.

需要考虑的一件重要事情是 equalshashCode 之间的合同。也就是说,如果您覆盖 equals,则必须以一种方式覆盖 hashCode,使其 returns 对于两个相等的实例具有相同的值。您对 equals 的实施。换句话说,以下规则必须始终成立:

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

无论何时实现 equals,你都应该始终实现 hashCode,因为即使 从未将你的对象放在 HashMap 中,你也不知道什么您正在使用的图书馆可能会这样做。图书馆可以在不通知您的情况下自由依赖您的对象 hashCode

即使您只是让 IDE 与 equals 一起自动生成 hashCode,或者即使只是

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

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

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

  1. 您的对象可能不会存储在 HashMapHashSet 今天,但六个月后,您可能会决定这样做,事情似乎会正常工作,直到它们可怕地崩溃。那时,你会对自己说“%$^^&%*& 我应该实施 hashCode!”

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

  3. 您可能将对象交给某个图书馆,而您并不知道,该图书馆可能想将您的对象存储在基于哈希的集合中。

  4. 如果您的对象曾经存储在容器对象中,即使该容器本身不是基于哈希的,容器的 hashCode通常在逻辑上取决于您对象的 hashCode。例如,参见 Arrays.hashCode or Optional.hashCode.

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

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