关于HashMap,在面试中几乎是必问的考点,记得我第一次面试,面试官上来就是说一下HashMap的put方法。不过当时还好做好了准备,这些也是能够轻松回答出来。值得注意的是,从JDK1.7到JDK1.8HashMap做了大量的改进。如果在回答有关HashMap问题时,能够分别说出1.7和1.8的区别的话,那么能够为你面试加一点分的。
put方法的流程如下:
- 进入到put方法之后,首先会将你给定的key通过hash算法以及与运算的方法将其运算得出数组的下标
- 如果数组的下标位置元素为空,则将对应的key value 封装成一个对象放入该数组位置。(JDK1.7中的叫做Entry对象 ,JDK1.8中的叫做Node对象)其实也就是存放key value键值对的对象而已
- 如果数组下标元素不为空的话,那么就要分jdk版本以及链表的长度进行讨论
(1)如果是JDK1.7的话,会先判断是否需要扩容,如果要扩容就先进行扩容,如果不用扩容的话就将key value封装成Entry对象。使用头插法的方式将该Entry对象添加到当前位置的链表中
(2)如果是JDK1.8的话,会先判断该位置上Node对象的类型是属于链表还是红黑树
a:如果Node是红黑树节点的话,会将key value封装成一个红黑树的Node节点将其添加到红黑树中,并且在这个过程中会判断红黑树是否存在要插入的key,如果存在该key,则直接更新value即可。
b: 如果该位置上Node节点的类型是链表的话,同样将该key value 封装成一个链表Node节点。然后使用尾插法的方式插入到该链表的最后位置中,在进行遍历的时候,同样会遍历链表的key值,如果存在插入的key值的话,那么直接更新value值即可。如果不存在就插入到链表的最后一个位置上。插入到链表之后,会将链表的长度更新,如果链表长度大于等于8的话,会将该链表更新会红黑树。
c: 将key value封装成Node对象将其插入到链表或者红黑树中后,在判断是否需要扩容,如果需要就进行扩容的操作,如果不需要扩容那么就退出put方法。返回执行的操作。
ps:这里你可能会问为什么是在链表长度大于等于8的情况下会进行转化,其实也就是为了减少在链表中的查询时间。在链表中的查询的时间复杂度为O(n/2),而红黑树的查询的时间复杂度为O(log(n))在。如果长度为8的话,那么链表查询时间复杂度为4,为红黑树的时间复杂度为3。但是如果在小于8的人情况下并不会有太多的时间复杂度的提升,反而会因为转换为红黑树的过程降低效率。