如果 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
.
需要考虑的一件重要事情是 equals
和 hashCode
之间的合同。也就是说,如果您覆盖 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] 中=].有几个原因。
您的对象可能不会存储在 HashMap
或 HashSet
今天,但六个月后,您可能会决定这样做,事情似乎会正常工作,直到它们可怕地崩溃。那时,你会对自己说“%$^^&%*& 我应该实施 hashCode
!”
您的对象可能会被其他人使用,并且他们希望您实现hashCode
。当 他们 将您的对象存储在 HashMap
中并且它不起作用时,他们会说 "that %$^^&%*& Aaron should have implemented hashCode
!"
您可能将对象交给某个图书馆,而您并不知道,该图书馆可能想将您的对象存储在基于哈希的集合中。
如果您的对象曾经存储在容器对象中,即使该容器本身不是基于哈希的,容器的 hashCode
通常在逻辑上取决于您对象的 hashCode
。例如,参见 Arrays.hashCode
or Optional.hashCode
.
hashCode
有时用于短路相等性检查。
归根结底,hashCode
/equals
合同的要点是每个人都依赖合同来正确执行。关于遵守合同的假设贯穿于整个大型系统,而不仅仅是基于哈希的集合。
我最近一直在学习 hashCode 函数和 HashMap,并尝试为我自己的 classes 创建我自己的 hashCode 函数。从我所做的研究来看,从实际的角度来看,需要覆盖 hashCode 的唯一原因似乎是 class 将用作 HashMap 中的键,或者 hashCode函数在别处使用。我知道这是要覆盖的 equals 和 hashCode 合同的一部分,将来另一个用户可能想在 HashMap 中使用它,但为了理解起见,我想知道 class 是否是 从未用作键,我还需要重写hashCode函数吗?
没有。但请记住 HashMap
中的键与 HashSet
中的值相同,因此您也无法将该对象存储在 HashSet
中(至少如果您打算使用它是为了内容平等)。
我认为你是正确的,如果你没有在键中使用你的对象或任何其他基于散列的数据结构,你不需要覆盖 Object.JVM 的散列码方法提供散列码的默认实现。
总会有 hashCode
的默认实现在内部使用身份哈希码。也就是说 class 可以在 HashSet
中使用,甚至可以作为 HashMap
中的键,但这不会非常有效或有意义 - 使用 [=13 没有意义=] 没有实施 equals
.
需要考虑的一件重要事情是 equals
和 hashCode
之间的合同。也就是说,如果您覆盖 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] 中=].有几个原因。
您的对象可能不会存储在
HashMap
或HashSet
今天,但六个月后,您可能会决定这样做,事情似乎会正常工作,直到它们可怕地崩溃。那时,你会对自己说“%$^^&%*& 我应该实施hashCode
!”您的对象可能会被其他人使用,并且他们希望您实现
hashCode
。当 他们 将您的对象存储在HashMap
中并且它不起作用时,他们会说 "that %$^^&%*& Aaron should have implementedhashCode
!"您可能将对象交给某个图书馆,而您并不知道,该图书馆可能想将您的对象存储在基于哈希的集合中。
如果您的对象曾经存储在容器对象中,即使该容器本身不是基于哈希的,容器的
hashCode
通常在逻辑上取决于您对象的hashCode
。例如,参见Arrays.hashCode
orOptional.hashCode
.hashCode
有时用于短路相等性检查。
归根结底,hashCode
/equals
合同的要点是每个人都依赖合同来正确执行。关于遵守合同的假设贯穿于整个大型系统,而不仅仅是基于哈希的集合。