关于标题的问题,看了许多文章,质量很一般,把人整麻了。最近看到讲的很好的课程,及时把知识进行总结,并在此分享给大家,求点赞支持!
1.put过程
在JDK1.8中,对hashMap进行put操作时,首先根据要插入的键值对的key,计算得到原始哈希值A。根据A再计算二次哈希值B,桶下标(数组下标)=B%数组容量Capacity,从而得到该键值对的插入位置:桶下标。
2.扩容和树化
2.1为什么要扩容?
当哈希冲突比较频繁(多个键值对的键的哈希值相同,即多个键值对的插入位置一样)时,链表长度会变得很长,这样一来,哈希表的查找时间复杂度就从O(1)退化成O(n)。这里解释一下,O(n)是比较极端的情况,但仍有可能发生。因此为了降低查找时间复杂度,必须对链表长度进行缩减!
要降低链表长度,显然要减少哈希冲突才行。而桶下标(数组下标)=B%数组容量Capacity,将数组容量值变大,即对数组容量进行扩容,会使得计算得到的桶下标的值更加分散,从而达到目的。
这里解释一下,即使扩容前数组中的所有元素都有自己的桶下标,但是在扩容时,需要重新计算桶下标。
2.2什么时候扩容?
首先区分两个概念:数组容量和数组元素个数。把数组看成是一个500毫升的烧杯,那么数组容量就是500毫升,数组元素个数就是烧杯中水的体积。一个是静态值,一个是实时的值。关于扩容有如下两个机制。
2.2.1 扩容机制1
在数组容量小于等于64的情况下:当Capacity*0.75≤数组元素个数<64时,数组容量会变为原来的2倍;当链表长度大于8时,数组容量会变为原来的2倍。
2.2.1扩容机制2
在数组容量大于64的情况下:当链表长度大于8时,链表转变成红黑树,提高查找效率为O(logN),logN和树高一个量级。
后续继续对HashMap底层原理进行补充,欢迎关注跟踪!