我正在研究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)))
有没有解释为什么这样做?谢谢。
答案 0 :(得分:8)
似乎导致你混淆的是两件事:
<强> 1。比较哈希值(通常非常快)比直接比较键更快。
<强> 2。在==运算符中,如果第一个条件为假,则不会检查第二个条件。
首先比较哈希值,这很快:
当它们不相等时,你知道键也不相等,你就完成了。
当它们相等时,你也不知道键是否相等,所以你必须比较(相对)慢的键。
由于大多数键不相等,大多数时候你只比较哈希。只有当密钥相等时(或者由于哈希冲突导致哈希值相等),您才比较密钥,这很少见,因此您可以获得性能优势。
答案 1 :(得分:2)
这是检查两个值是否可能相等的有效方法。
hashcode
任务的合同:
如果两个对象根据equals(Object)方法相等,则对两个对象中的每个对象调用hashCode方法必须生成相同的整数结果。
因此,如果哈希值不同,则无需进行进一步检查。
由于HashMap
需要键的哈希码,无论如何选择要放入条目的桶,权衡是每个条目存储一个额外的int
,而不必重复计算它并且必须更频繁地为密钥执行equals
。 HashMap
更适合快速检索和插入,而内存效率则更低。
<子>
附注:HashMap
依赖于未以任何方式改变的密钥,这些密钥会在equals
和hashcode
方面改变其“身份” - 虽然这看起来很明显,但未明确提及在HashMap
的JavaDocs中,过去曾引发过一些问题:Are mutable hashmap keys a dangerous practice? - 这是更为笼统的Map
contract:
注意:如果将可变对象用作映射键,则必须非常小心。如果在对象是地图中的键时,以影响等于比较的方式更改对象的值,则不指定映射的行为。