HashMap

为什么是2的n次方?
我们知道,在初始化hashMap时,容量大小Capacity必需满足为2的n次方,为什么需要这个规定呢?

最近在HashMap源码中看到了这样一个表达式

i = (cap - 1) & hash   //putVal方法中摘抄出来的一个表达式

对里面的索引表达式 (cap -1) & hash 很不解,于是就自己手动模拟了几个值算了一下,

当n=3时:
cap = 2^n = 8;
用8位二进制表示cap:
0000 1000
用8位二进制表示cap - 1:
0000 0111
然后随便取几个Hash值(8位二进制表示):
hash1 = 0010 1000
hash2 = 1101 0011
hash3 = 1111 1111
hash4 = 0000 0001
hash5 = 0000 0010
hash6 = 0100 0101
hash7 = 1001 0100
然后计算(cap - 1) & hash 的值(8位二进制表示):
hash1: 0000 0111 & 0010 1011 = 0000 0000 = 0
hash2: 0000 0111 & 1101 0011 = 0000 0011 = 3
hash3: 0000 0111 & 1111 1111 = 0000 0111 = 7
hash4: 0000 0111 & 0000 0001 = 0000 0001 = 1
hash5: 0000 0111 & 0000 0010 = 0000 0010 = 2
hash6: 0000 0111 & 0100 0101 = 0000 0101 = 5
hash7: 0000 0111 & 1001 0100 = 0000 0100 = 4

可以看出,当容量为2的n次方时,无论hash值为多少,最后计算得到的索引值有且仅有落在数组上(0到2^n-1的闭区间上)所有点的可能。
当容量不为2的n次方时,无论hash值为多少,最后计算得到的索引值有且仅有落在数组中部分点的可能。
只有当可以分布在数组的所有点上时,才能减小hash碰撞的可能性,这也就是为什么会有容量大小Capacity必需满足为2的n次方的规定 了。

那么,问题又来了,我要是传入一个不满足规定的值,这个规定是怎么强制执行的呢?上代码

static final int tableSizeFor(int cap) {
        int n = cap - 1;
        n |= n >>> 1;
        n |= n >>> 2;
        n |= n >>> 4;
        n |= n >>> 8;
        n |= n >>> 16;
        return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 实际上,HashSet 和 HashMap 之间有很多相似之处,对于 HashSet 而言,系统采用 Hash 算...
    曹振华阅读 2,526评论 1 37
  • HashMap 是 Java 面试必考的知识点,面试官从这个小知识点就可以了解我们对 Java 基础的掌握程度。网...
    野狗子嗷嗷嗷阅读 6,705评论 9 107
  • 本文转自 https://zhuanlan.zhihu.com/p/21673805 美团点评技术团队· 3 个月...
    抓兔子的猫阅读 1,079评论 0 1
  • 1. 好好思考一下,你有没有一个写文章时可供征引阐发的资源库? 目前还没有一个比较完善的可供征引阐发的资源库。想要...
    小安随笔阅读 201评论 9 2
  • 一座古老的城堡,被历史这座雕刻家打磨的锃锃发亮,在漫漫黑夜中散发着幽幽的绿光,神秘与未知将它笼罩的几乎密不透风...
    清竹的小世界阅读 1,502评论 8 31