题目来源:https://zhuanlan.zhihu.com/p/86536581
java基础
01 Hashmap 源码级掌握,扩容,红黑树,最小树化容量,hash冲突解决,有些面试官会提出发自灵魂的审问,比如为什么是红黑树,别的树不可以吗;为什么8的时候树化,4不可以吗,等等
-
什么时候进行扩容
当size == 桶的数量 乘以 负载因子时进行扩容,通过桶的数量 乘以 2的方式来完成。
当threshold = 自定义桶的数量 * 负载因子进行扩容。 -
什么时候红黑树和链表之间的转换
刚开始的时候,table中数组的个数大于64时。当一个node节点处重复的元素>8时,将链表转换为红黑树。当红黑树的节点个数<6时,从红黑树转换为链表。 -
hash冲突是怎么进行解决的
hash = key的二进制表示。通过在冲突的位置添加链表或者红黑树来进行解决 -
size必须是2的整数次方原因
当size是2时有以下两个好处:
- 在计算table中的index时, index=hash&(n-1)。一般用%来计算index,但是%效率低。我们发现,当n是2的整数次幂时,%和&的作用是一样的,并且&效率会高很多
- 在经过扩容以后,需要把选在的数据进行挪动,这时候取2的整数次幂速度会快很多
-
get和put方法流程
get方法流程:
根据key值,计算的对应的index。判断table[index]节点中的key是否是对应的值,是则返回。否则,在table[index]的位置进行搜索(包括链表搜索或者红黑树搜索)
put方法流程:
首先判断是否要进行懒加载,是则进行。
根据key计算得到对应的index,判断table[index]是否为空,是则存放在这个位置。否则遍历table[index]的位置,如果该位置处已经有key值这个节点,更新这个节点对应的value。否则进行插入新节点。插入新节点后,需要判断当前链表个数是否=8,是则判断table的数组个数是否是64,如果小于64,则进行扩容,如果大于64,则将链表转换为红黑树 -
resize方法
主要是两个作用:
一 懒加载的过程中,完成hashmap的容量大小的设置
二 扩容的过程中,完成hashmap容量的扩充 -
影响HashMap的性能因素(key的hashCode函数实现、loadFactor、初始容量)
hashCode函数:hashcode=key的二进制。通过hashcode高16位和低16位的位运算操作,来给出hash。可以保证hash过程中的随机性
loadFactor:装载因子。是决定是否是时候进行扩容的计算条件之一。当较小时,put /get代价小,需要空间大;当较大时,put/get代价大,需要空间小
初始容量:16。 -
HashMapkey的hash值计算方法以及原因(见上面hash函数的分析)
hash =hashcoder
可以提高随机性。 -
HashMap内部存储结构:Node数组+链表或红黑树
-
table[i]位置的链表什么时候会转变成红黑树
判断当前table的数组容量大于64时,且一个数组中跟的链表的个数达到了8,此时将链表抓换位红黑树。 -
HashMap主要成员属性:threshold、loadFactor、HashMap的懒加载
threshold = 数组大小 * loadFactor。是决定是否需要进行扩容的边界。
hashMap懒加载:当往HashMap中put第一元素时,才会进行初始化 -
HashMap的get方法能否判断某个元素是否在map中
不可以。因为hashmap中允许key取到null -
HashMap线程安全吗,哪些环节最有可能出问题,为什么?
HashMap不是线程安全的。会发生在put操作引是的扩容。HashMap的默认容量是16, 当100个线程进行put时,会发生扩容混乱。因为没有任何的所来保证并发安全。 -
HashMap的value允许为null,但是HashTable和ConcurrentHashMap的valued都不允许为null,试分析原因?
由于hashmap允许key的值为null。因此调用get函数且返回为空时,会发生混淆。不知道到底是key为null,还是key对应的value为null -
HashMap中的hook函数(后面讲解LinkedHashMap时会讲解,这可作为HashMap的延伸知识,增加面试官对你的印象)
01 Hashmap 源码级掌握,扩容,红黑树,最小树化容量,hash冲突解决,有些面试官会提出发自灵魂的审问,比如为什么是红黑树,别的树不可以吗;为什么8的时候树化,4不可以吗,等等**
-
什么时候进行扩容
当size == 桶的数量 乘以 负载因子时进行扩容,通过桶的数量 乘以 2的方式来完成。
当threshold = 自定义桶的数量 * 负载因子进行扩容。 -
什么时候红黑树和链表之间的转换
刚开始的时候,table中数组的个数大于64时。当一个node节点处重复的元素>8时,将链表转换为红黑树。当红黑树的节点个数<6时,从红黑树转换为链表。 -
hash冲突是怎么进行解决的
hash = hashcodeg高16位和低16位的位运算。通过在冲突的位置添加链表或者红黑树来进行解决 -
size必须是2的整数次方原因
当size是2时有以下两个好处:
- 在计算table中的index时, index=hash&(n-1)。一般用%来计算index,但是%效率低。我们发现,当n是2的整数次幂时,%和&的作用是一样的,并且&效率会高很多
- 在经过扩容以后,需要把选在的数据进行挪动,这时候取2的整数次幂速度会快很多
-
get和put方法流程
get方法流程:
根据key值,计算的对应的index。判断table[index]节点中的key是否是对应的值,是则返回。否则,在table[index]的位置进行搜索(包括链表搜索或者红黑树搜索)
put方法流程:
首先判断是否要进行懒加载,是则进行。
根据key计算得到对应的index,判断table[index]是否为空,是则存放在这个位置。否则遍历table[index]的位置,如果该位置处已经有key值这个节点,更新这个节点对应的value。否则进行插入新节点。插入新节点后,需要判断当前链表个数是否=8,是则判断table的数组个数是否是64,如果小于64,则进行扩容,如果大于64,则将链表转换为红黑树 -
resize方法
主要是两个作用:
一 懒加载的过程中,完成hashmap的容量大小的设置
二 扩容的过程中,完成hashmap容量的扩充 -
影响HashMap的性能因素(key的hashCode函数实现、loadFactor、初始容量)
hashCode函数:hashcode=key的二进制。通过hashcode高16位和低16位的的位运算操作,来给出hash。可以保证hash过程中的随机性
loadFactor:装载因子。是决定是否是时候进行扩容的计算条件之一。当较小时,put /get代价小,需要空间大;当较大时,put/get代价大,需要空间小
初始容量:16。 -
HashMapkey的hash值计算方法以及原因(见上面hash函数的分析)
hash = hashcode=key的二进制
可以提高随机性。 -
HashMap内部存储结构:Node数组+链表或红黑树
-
table[i]位置的链表什么时候会转变成红黑树
判断当前table的数组容量大于64时,且一个数组中跟的链表的个数达到了8,此时将链表抓换位红黑树。 -
HashMap主要成员属性:threshold、loadFactor、HashMap的懒加载
threshold = 数组大小 * loadFactor。是决定是否需要进行扩容的边界。
hashMap懒加载:当往HashMap中put第一元素时,才会进行初始化 -
HashMap的get方法能否判断某个元素是否在map中
不可以。因为hashmap中允许key取到null -
HashMap线程安全吗,哪些环节最有可能出问题,为什么?
HashMap不是线程安全的。在并发插入元素的时候,有可能出现带环链表,让下一次读操作出现死循环。会发生在put操作引是的扩容。HashMap的默认容量是16, 当100个线程进行put时,会发生扩容混乱,到最后会造成链表环。因为没有任何的锁来保证并发安全。解放方案:concurrentMap更加适用于高并发的场景。 -
HashMap的value允许为null,但是HashTable和ConcurrentHashMap的valued都不允许为null,试分析原因?
由于hashmap允许key的值为null。因此调用get函数且返回为空时,会发生混淆。不知道到底是key为null,还是key对应的value为null -
HashMap中的hook函数(后面讲解LinkedHashMap时会讲解,这可作为HashMap的延伸知识,增加面试官对你的印象)