HashMap的底层数据结构是什么?
jdk1.7和jdk1.7前使用的是数组,链表
jdk1.8和jdk1.8后使用的是数组,链表,红黑树
HashMap的put方法流程是怎么样的?
1.先获取key的hash值
注意:通过key获取hash值,直接获取hash值就可以了,但是这里把key的hash值的前16个字节和后16个字节用^来运算,是为什么呢? 使hash值更加随机,防止避免通过hash值计算出来的索引大概率的为一个索引值
2.通过上一步获取的hash值计算索引
通过源代码我们可以发现计算索引的公式为 (n-1) & hash, n为数组长度hashMap默认数组长度为16,hash为上一步计算出来的hash值
HashMap中数组的长度默认是16,每次扩容1倍,这是为什么呢?
通过上面的代码我们可以发现计算索引的值和hash值与数组的长度有关,通过&来计算
16-1 =15 , 15的二进制值为 1111
32-1 = 31 , 31的二进制值为 11111
所有二的等次幂减1的二进制所有位置的值都为 1,获取的hash值是随机的,所以当hashMap的数组长度为2的等次幂时,计算出来的索引是随机的,减少了hash碰撞,提高了hashMap性能
3.把数据存储到指定的索引位置中,如果该索引位置有值,就会在该索引位置形成一条链表,新增加的数据插入在原来的数据前面
jdk7是头插法,把新增加的数据插入在链表头部,头插法在多线程的情况下数组扩容,会导致循环链表的问题出现
jdk8是尾插法,把新增加的数据插入在链表最后面,尾插法避免循环链表这个问题
HashMap的get方法流程是怎么样的?
1.先通过key获取key的hash值,通过计算获取元素所在数组的索引,获取数据,使用hashCode和equals方法来比较key是否一样,如果不一样遍历列表,再比较
HashMap的数组什么时候扩容?
HashMap中有一个负载因子值为 0.75,当 HashMap中的元素个数* 0.75 = HashMap中的数组长度时,HashMap就会扩容,数组扩大到原来的一倍长度
jdk7与jdk8中HashMap做了哪些改变?
1.jdk8中添加了红黑树数据结构,当链表长度超过8时,会把链表转成红黑树,当链表长度小于等于6的时候会把红黑树转成链表
2.jdk8中使用的是尾插法,jdk7中使用的是尾插法
HashMap是线程安全的吗?
HashMap不是线程安全的,线程安全的map有HashTable和ConcurrentHashMap
推荐使用ConcurrentHashMap它的效率比HashTable要高,它采用的是分段锁
HashTable采用的是synchronized
欢迎大家关注我的微信公众号