HashMap扩容大小为什么是2的幂

1、前言

  在回答这个问题之前,我们可以回顾一下HashMap的存取过程,当执行putVal的操作的时候,

  • 首先检查大小,看是否需要扩容(默认元素超过最大值的0.75时扩容),如果需要扩容就进行扩容

  • 然后计算出key的hashcode,根据hashcode定位数值所在的bucketIndex

  • 如果该位置上没有元素,就直接插入,结束

  • 如果该位置上有元素就使用equal比较是否相同

  • 如果key相同就把新的value替换旧的value,结束

  • 如果key不同,就继续遍历,找到根节点,如果没找到key的话,就构造一个新的节点,然后把节点插入到链表尾部,表示put成功(jdk 1.8 之后链表长度超过阈值就会转化为红黑树)

2、详解

  好了,一个put操作就这样完成了,按照我们理想的状况,hashMap的存取就是O(1),也就是直接根据hashcode就可以找到它,每个bucket只存储一个节点,链表指向都是null,这样就比较开心了,不要出现一个链表很长的情况。

  所以我们希望它能分布的均匀一点,如果让我们设计的话,我们肯定是直接对长度取模-----hashcode % length,但HashMap的设计者却不是这样写的,它写成了2进制运算,如下:

static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}

index = (n - 1) & hash

  为什么设计成(n - 1) & hash 这样呢?在 n 为 2次幂的情况下时,(n - 1) & hash ≈ hash % n ,因为2进制的运算速度远远高于取模,所以就使用了这种方式,所以要求为2的幂。

  我们可以看到它求hash的过程,将32位的hashCode值向右移动16位,高位补0,也就是只要了高16位,这是为什么呢?因为hashcode的计算方法导致哈希值的差异主要在高位,而 (n - 1) & hash是忽略了容量以上的高位的,所以 使用h >>>16就是为了避免类似情况的哈希冲突

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • HashMap 是 Java 面试必考的知识点,面试官从这个小知识点就可以了解我们对 Java 基础的掌握程度。网...
    野狗子嗷嗷嗷阅读 6,714评论 9 107
  • 1.概述 HashMap是日常java开发中常用的类之一,是java设计中非常经典的一个类,它巧妙的设计思想与实现...
    Garwer阅读 2,268评论 1 28
  • 作为标准一个大三党,在你们高考结束后咨询了众多学长学姐,迫不及待有很多想法想要和你们分享,我几乎写了篇三千字的论文...
    Jenny爱青梅阅读 160评论 1 0
  • 小时候,冒险是打娘胎里带出来的一种野性。在这种野性驱使之下,12岁之前,我们一群同龄的孩子暗地里进行过许多秘密活动...
    痒痒不挠阅读 381评论 0 1
  • 晶莹剔透的雪花, 如同曼妙玲珑的少女, 悠然落下, 投入大地的怀抱。 大地伸出双臂, 满心欢喜地与雪花相拥相依, ...
    雨花石_fc62阅读 354评论 0 2