前言
早上在面一家公司的时候 被问到有了equals为什么还要hashcode方法 本来是一个比较简单的问题 但是在讲完各自的作用后想讲讲自己的理解的时候突然卡壳 所以写一篇文章来梳理一下这个逻辑
分析
首先 equals和hashcode方法通常是成对出现的 在使用一些哈希结构的时候非常重要 比如HashMap HashTable等
- equals方法 用于判断两个对象是否相等 我们可以重写equals方法 来决定两个对象相等的逻辑 比如在String类中 重写了equals方法 认为两个字符串相等 那就是相等的
- hashcode方法 返回一个整数哈希码 从而快速定位存储位置 提高查询效率
理解完他们的作用后 我们来看一下HashMap的源码 我这里展示了put的部分源码
ini
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
boolean evict) {
Node<K,V>[] tab; Node<K,V> p; int n, i;
if ((tab = table) == null || (n = tab.length) == 0)
n = (tab = resize()).length;
if ((p = tab[i = (n - 1) & hash]) == null)
tab[i] = newNode(hash, key, value, null);
else {
Node<K,V> e; K k;
//如果哈希值相等
if (p.hash == hash &&
//判断地址相同 或者 逻辑相同
((k = p.key) == key || (key != null && key.equals(k))))
e = p;
else if (p instanceof TreeNode)
e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
else {
for (int binCount = 0; ; ++binCount) {
if ((e = p.next) == null) {
p.next = newNode(hash, key, value, null);
if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
treeifyBin(tab, hash);
break;
}
// //如果哈希值相等
if (e.hash == hash &&
//地址相同 或者 逻辑相同
((k = e.key) == key || (key != null && key.equals(k))))
break;
通过查看源码可以发现 hashcode的计算值
- 用于寻找插入位置 并且用于快速判断两个元素是否相同
- 如果相同再判断两个元素是否是同一个元素
总结
总的来说
分为两方面 提高效率 保证对象唯一性
hashcode提供了一种快速计算对象哈希值的方式 可以快速定位到元素应该存放在哪 提高了查询和存放效率
另外一方面 和equals做协同 保证数据的一致性和完整性 通过HashMap的源码也可以看到 他会缓存已有键值对的哈希码 用于快速判断元素是否存在 如果两个对象的hashcode值不同 那么就不可能是同一个对象 如果相同 再通过equals判断两个对象是否相等 既保证了正确性 又提高了性能