设为首页 加入收藏

TOP

HashMap 实现原理(二)
2017-10-27 09:07:02 】 浏览:300
Tags:HashMap 实现 原理
ey) == key || (key != null && key.equals(k)))) return e; } while ((e = e.next) != null); } } return null; }

判断元素相等的设计比较经典,利用了bool表达式的短路特性:先比较hash值;如果hash值相等,就通过==比较;如果==不等,再通过equals方法比较。hash是提前计算好的;如果没有重载运算符(通常也不建议这样做),==一般直接比较引用值;equals方法最有可能耗费性能,如String的equals方法需要O(n)的时间,n是字符串长度。一定要记住这里的判断顺序,很能考察对碰撞处理源码的理解。

针对HashMap的使用,此处要注意覆写hashCode和equals方法时的两个重点:

  • 覆写后,一定要保证equals判断相等的时候,hashCode的返回值也相等。
  • 对于选作key的类,要保证调用put与get时hashCode的返回值相等,equals的性质相同。

resize

resize是HashMap中最难理解的部分。

调用put方法时,如果发现目前的bucket占用程度已经超过了loadFactor,就会发生resize。简单的说就是把bucket扩充为2倍,之后重新计算index,把节点再放到新的bucket中。

javadoc中这样说:

Initializes or doubles table size. If null, allocates in accord with initial capacity target held in field threshold. Otherwise, because we are using power-of-two expansion, the elements from each bin must either stay at same index, or move with a power of two offset in the new table.

即,当超过限制的时候会resize,又因为我们使用的是2次幂的扩展,所以,元素的位置要么是在原位置,要么是在原位置再移动2次幂的位置。

怎么理解呢?例如我们从16扩展为32时,具体的变化如下:

假设bucket大小n=2^k,元素在重新计算hash之后,因为n变为2倍,那么新的位置就是(2^(k+1)-1)&hash。而2^(k+1)-1=2^k+2^k-1,相当于2^k-1的mask范围在高位多1bit(红色)(再次提醒,原来的长度n也是2的次幂),这1bit非1即0。如图:

所以,我们在resize的时候,不需要重新定位,只需要看看原来的hash值新增的那个bit是1还是0就好了,是0的话位置没变,是1的话位置变成“原位置+oldCap”。代码比较长就不贴了,下面为16扩充为32的resize示意图:

这个设计非常的巧妙,新增的1bit是0还是1可以认为是随机的,因此resize的过程均匀的把之前的冲突的节点分散到新的bucket中了。

参考:

首页 上一页 1 2 下一页 尾页 2/2/2
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇Java 高并发综合 下一篇面试中单例模式有几种写法

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目