1、HashMap数据结构
jdk8之前的数据结构是数组链表
jdk8以后的数据结构是数组链表的红黑树
并发时,如果发生扩展,可能会发生循环链表,在get运行过程中接触死循环,引起CPU 100%的问题,因此必须避免在并发环境中使用HashMap
2、HashMap为什么选择数组链表中红黑树的数据结构
序列:保存和获取效率最高,时间复杂度为o(1)
链表:要解决混列冲突问题,必须遍历链表中的所有数据。 时间的复杂性是o(n )
红色树:优化链表性能,使搜索、插入、删除等操作时间的复杂性达到o(logn )
3、为什么不用红黑树直接用链表达到指定长度时转换为红黑树?
元素数量少,红黑树与链表相比效率低,红黑树失去平衡,需要自旋(左旋、右旋)才能维持树的自身平衡
4、链表转移到红黑树的阈值来源和链表转移到红黑树的条件
阈值来源:
统计链表转换为红黑树的阈值,概率分布(概率统计)为(一个元素、两个元素、三个元素)的列表出现的概率
转换条件:
仅当数组长度大于或等于64且数组元素链表长度大于或等于9时转换
5、为什么序列长度达到64才可能转化为红黑树?
finalvoidtreeifybin(node[]tab,int hash ) {
int n,index; 节点e;
//todo数组的长度小于64时,不会转换为红黑树
if(tab==null||(n=tab.Length ) MIN_TREEIFY_CAPACITY () ) ) ) ) ) 0
resize (;
elseif () e=tab [索引=(n-1 ) hash]!=空) {
TreeNode hd=null,tl=null;
do {
treenode p=替换趋势(e,null );
if(TL==null ) )。
高清=p;
else {
p.prev=tl;
tl.next=p;
}
tl=p;
}while((e=e.next )!=null;
if () tab[index]=HD高清)!=null )
高清.三叉树(tab;
}
}
复制代码
6、为什么链表中转红黑树的阈值不是8而是9?
finalvputval(inthash,K key,V value,布尔在线,
布尔事件) {
节点[ ]选项卡; 节点p; int n,I;
//todo初始化大小(扩展操作)
(if () tab=table )==null|| (n=tab.length (==0) ) ) ) ) ) ) )
n=(tab=resize () ).length;
//todo通过混列计算判断对应的数组元素是否有值
if () p=tab(I=(n-1 ) hash] )==null ) )
如果没有//todo,则直接插入元素
tab[I]=newnode(hash,key,value,null );
else {
//todo到此为止,请注意与该散列值对应的数组元素中已经有元素
节点e; k;
//todo判断key是否存在,如果存在则覆盖旧的值
if(p.hash==hash
() k=p.key )==key|(key!=nullkey.equals(k ) )
e=p;
//todo判断是否是红黑树
elseif(pinstanceoftreenode ) )。
e=() treenode ) p ).puttreeval ) this,tab,hash,key,value );
//todo进入链表逻辑
else {
for(intbincount=0; binCount ) {
if () e=p.next )==null ) {
创建//todonode节点
p.next=newnode(hash、key、value、null );
//7以上,循环8次,创建8个节点,加上以前存在的1个节点,直到链表长度为9,才变换红黑树
if (bincount=tree ify _ threshold-1 )//-1 for 1st
treeifybin(tab,hash );
布雷克;
}
if(e.hash==hash
() k=e.key )==key|(key!=nullkey.equals(k ) )
布雷克;
p=e;
}
}
if(e!=null(//existingmappingforkey
V oldValue=e.value;
if (! onlyIfAbsent || oldValue==null )
e .值=值;
afternodeaccess(e;
返回载荷值;
}
}
模具计数;
大小阈值(if ) )。
resize (;
自动识别(evict;
返回空值;
}
复制代码
7、为什么HashMap建议序列容量为2的指数次方
容量初始化:
输入容量将转换为最接近此数且大于此数的2的指数次幂,而不是2的指数次幂
为了提高效率,混码%长度的取模效率过低,位运算混码(长度-1)效率高,JDK版本1.7的序列扩展会产生大量的混码
8、为什么负荷因子为0.75?
为了解决hash冲突问题
负载因子为1或更大时,碰撞的可能性更高,链表的长度越长,查找时间的复杂性越高(
负载率小于等于0.5时,查询快,空间切换时间短,混列冲突低
0.75这个数值被牛顿二项式推翻,在时间和空间上进行折中处理