- hahmap数据结构
JDK1.7中,HashMap采用位桶+链表实现,即使用链表处理冲突,同一hash值的链表都存储在一个链表里。但是当位于一个桶中的元素较多,即hash值相等的元素较多时,通过key值依次查找的效率较低;
JDK1.8中,HashMap采用位桶+链表+红黑树实现,当链表长度超过阈值(8)时,将链表转换为红黑树,这样大大减少了查找时间
- HashMap中CRUD操作的底层实现原理是什么?
PUT
1. 通过key计算出一个hashcode
2. 通过hashcode与“与操作”计算出一个数组下标
3. 在把put进来的key,value封装为一个entry对象
4. 判断数组下标对应的位置,是不是空,如果是空则把entry直接存在该数组位
置
5. 如果该下标对应的位置不为空,则需要把entry插入到链表中
6. 并且还需要判断该链表中是否存在相同的key,如果存在,则更新value
7. 如果是JDK7,则使用头插法;如果是JDK8,则会遍历链表,并且在遍历链表的过程中,统计当前链表的元素个数,如果超过8个,则先把链表转变为红黑树,并且把元素插入到红黑树中
头插法:冲突的时候,将后面插入的元素放到链表的头部;
GET
- JDK8中链表转变为红黑树的条件?
1. 链表中的元素的个数为8个或超过8个
2. 同时,还要满足当前数组的长度大于或等于64才会把链表转变为红黑树。为什么?因为链表转变为红黑树的目的是为了解决链表过长,导致查询和插入效率慢的问题,而如果要解决这个问题,也可以通过数组扩容,把链表缩短也可以解决这个问题。所以在数组长度还不太长的情况,可以先通过数组扩容来解决链表过长的问题。
红黑树本质是一棵二叉查找树,但它在二叉查找树的基础上增加了着色和相关的性质使得红黑树相对平衡,从而保证了红黑树的查找、插入、删除的时间复杂度最坏为O(log n)。加快检索速率
- hashMap中的hash()
在hashmap中要找到某个元素,需要根据key的hash值来求得对应数组中的位置。如何计算这个位置就是hash算法。
- 为什么HashMap的数组的大小是2的幂次方数?
hashmap在进行CURD的时候要首先使用确定index,index = (n -1)&hash;根据以上公式,n不为2的幂次方数时,出现hash碰撞的概率大大增加,因此数组长度必须为2的幂次方数。
退一步讲:为什么使用index = (n -1)&hash?
获取index的逻辑仅需要保证,元素均匀分布,尽量避免hash冲突即可。当n为2次幂时,会满足一个公式:(n - 1) & hash = hash % n;而且hash时采用了二进制的位运算来提高计算速度,而不是使用常规的取模;
- 在高并发大流量的情况下,hashMap有什么问题吗,会不会造成cpu达到100%?如果会,那是在哪一步可能会出现这个问题呢(插入、删除、查找、扩容)?
jdk1.7中会造成,原因:插入元素的时候使用头插法,后面扩容的时候也先从头部获取元素
扩容前链表中元素顺序 :A---->B
扩容前链表中元素顺序 :B---->A
扩容为多步操作:数组扩容、元素转义,因此当多线程操作的时候,假如线程1完成了数组扩容,此时元素顺序 :A---->B,此时线程上下文切换;线程2完成了数组扩容、元素转义两步操作,链表中元素顺序 :B---->A。那么就会出现互相指向。
而 JDK 1.8 时已经变成了尾部插入
当链表数组的容量超过初始容量的0.75时,再散列将链表数组扩大2倍,把原链表数组的搬移到新的数组中。
参考文章:
HashMap与红黑树_Lin_Dong_Tian的博客-CSDN博客_hashmap红黑树
hashmap hash冲突怎么解决_HashMap原理_徐一僧的博客-CSDN博客
详解 HashMap 中的 hash 函数_得一的博客-CSDN博客_hash函数
为什么hashMap的容量扩容时一定是2的幂次_平凡之路无尽路的博客-CSDN博客_hashmap容量为什么是2的幂次hh
Java8中为什么使用红黑树?-技术圈