为什么HashMap的get()比较Java中的哈希值和键?

时间:2018-06-05 16:53:47

标签: java hashmap comparison hashcode

我正在研究JDK8中HashMap的实现。在get方法中,我看到下面的行,用于查找与给定键匹配的Node。

if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k))))

为什么需要将哈希值与密钥进行比较?为什么上面的行不写为:

if (((k = e.key) == key) || (key != null && key.equals(k)))

有没有解释为什么这样做?谢谢。

2 个答案:

答案 0 :(得分:8)

似乎导致你混淆的是两件事:

<强> 1。比较哈希值(通常非常快)比直接比较键更快。

<强> 2。在==运算符中,如果第一个条件为假,则不会检查第二个条件。

首先比较哈希值,这很快:

  • 当它们不相等时,你知道键也不相等,你就完成了。

  • 当它们相等时,你也不知道键是否相等,所以你必须比较(相对)慢的键。

由于大多数键不相等,大多数时候你只比较哈希。只有当密钥相等时(或者由于哈希冲突导致哈希值相等),您才比较密钥,这很少见,因此您可以获得性能优势。

答案 1 :(得分:2)

这是检查两个值是否可能相等的有效方法。

hashcode任务的合同:

JavaDocs of Object.hashCode

  

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

因此,如果哈希值不同,则无需进行进一步检查。

由于HashMap需要键的哈希码,无论如何选择要放入条目的桶,权衡是每个条目存储一个额外的int,而不必重复计算它并且必须更频繁地为密钥执行equalsHashMap更适合快速检索和插入,而内存效率则更低。

<子> 附注:HashMap依赖于未以任何方式改变的密钥,这些密钥会在equalshashcode方面改变其“身份” - 虽然这看起来很明显,但未明确提及在HashMap的JavaDocs中,过去曾引发过一些问题:Are mutable hashmap keys a dangerous practice? - 这是更为笼统的Map contract

  

注意:如果将可变对象用作映射键,则必须非常小心。如果在对象是地图中的键时,以影响等于比较的方式更改对象的值,则不指定映射的行为。