本过程参考网上资料以及哔哩哔哩网站鲁班学院-周瑜老师的讲课内容进行整理,仅供学习使用。感谢各位大佬!如有侵权请联系。
一、主要成员变量解析
二、HashMap底层结构
1、HashMap底层用的是数组+链表的格式,大概格式如下,为了方便直接写的entry节点内容,其实应该为entry的地址引用。
三、构造函数(构造函数只初始化了变量,当调用put时才会真正的初始化HashMap,为了避免内存浪费)
四、put过程(按照每一个步骤依次讲解)
4.1、初始化HashMap------>inflateTable(threshold);
重点解释一下roundUpToPowerOf2函数中的过程【如何判断一个数是2的次幂,规律就是只有一位字节(bit位)是1,其余全是0。】Integer.highestOneBit()函数过程是得到小于一个数的最大的2次幂数,也就是以下过程:
4.2 如果key为null,要放到table的第一个位置,然后判断第1个位置的是否为空、链表上是否已经有key为null的了,有的话覆盖
4.3 经过一系列的或运算、右移等骚操作得到hash
4.4 通过4.3计算出的hash以及hashmap的大小计算数组下标。
将值放入一个数组中,其实我们正常的思路是
(1)不能越界(计算出的index要在0到table.length-1区间内) (2)分布要均匀 =====通过这两个条件我们很容易联想到取模算法,也就是求余,但是求余的话效率比较低,最快的是直接操作位。
4.3计算出的hash是任意的数值 ,转换成二进制就是(任意的) ,与length进行&操作,要想不能越界,所以结果数要完全依赖于hash的低n位,所以就要求length的低n为必须全是1。【从这就能得知为什么hashmap的长度必须是2的次幂数】
1101 1010
0000 1111
& 1101 1010 完全只依赖于hash本身
4.7 加入新增的节点,头插法,然后移动链表,也就是将新插入节点的引用赋给table[index]
五、扩容过程,1.7中扩容需要满足两个条件,一是当前条数大于等于扩容阈值,二是计算出的index上不是null,扩容是二倍扩容
resize(2 * table.length);
重点讲一下扩容以及数据的迁移:
六、get过程
get就比较简单了,如果key为null,就取table[0]的节点上的值,比对链表上是否有null 的
如果key不为null,则计算hash、并得到index,然后比较table[index]上链表的key是否有传入的,有的话返回值