HashMap源码解读
提示:个人笔记,下面案例可供参考
HashMap(线程不安全):默认容量是16,加载因子是0.75,每次扩容 容量会增张两倍
JDK1.7:数组+链表:
JDK1.8:数组+链表+红黑树
链表长度大于8并且数组长度大于64 会变成红黑树
1.HashMap初始化容量为什么要2的幂次方?
计算流程:
1.会根据hashMap的key值获取hash值.
2.传入的初始化值减1与hash值进行’与‘运算.
3.计算出的结果为数组角标
1.1初始值不为2的幂次方时:
假设n为14,n-1的二进制为0000 1101,与hash值运算结果如下
假设n为13,n-1的二进制为0000 1100,与hash值运算结果如下
*可以看到这样会增加hash碰撞的几率(计算出的结果一样)
1.2初始值为2的幂次方时
假设n为16(2的幂次方),n-1的二进制位0000 1111,与hash值运算结果如下
假设n为8(2的幂次方),n-1的二进制位0000 1111,与hash值运算结果如下
2.将链表转换为红黑树
1.根据哈希表中元素个数确定是扩容还说树形化。
2.如果是树形化遍历桶中的元素,创建相同个数的树形节点,复制内容,建立联系。
3.然后让桶中的第一个元素指向新创建的树根节点,替换桶的链表内容为树形化内容。
3.HashMap扩容机制
1.当HashMap中的元素个数超过了数组大小(数组长度*负载因子)时,就会进行扩容。默认情况下,数组大小为16,那么当HashMap中的元素个数超过了16×0.75(默认)时,就会把数组的大小扩展为2×16=32,即扩大了一倍,然后诚信计算每个元素在数组中的位置。
2.当HashMap中的其中一个链表的对象个数如果达到了8个,此时如果数组长度没有达到64,那么HashMap会先扩容解决,如果已经达到了64,那么这个链表会变成红黑树,节点类型由Node变成TreeNode类型。如果树节点个数小于6时,会再把树转为链表。
3.扩容之后的节点要么就在原来的位置,要么就被分配到“原位置+旧容量”这个位置上。
4.在扩容HashMap的时候,不需要重新计算hash,只需要看看原来的hash值新增的那个bit是1还是0就可以了,是0的话索引没变,是1的话索引变成“原位置+旧容量”。
4.如何设置HashMap的初始化问题描述
1.我们想要在代码中创建一个HashMap的时候,如果我们已知这个map中即将存放的元素个数,给HashMap设置初始容量可以在一定程度上提升效率。公式:“所需要的使用个数/0.75+1“。
2.JDK并不会直接拿用户传进来的数字当默认容量,而是会进行一番运算,最终得到一个2的幂次方(3->4 ,7->8 ,9->16)。