实现原理:
将KEY放入数组 -> 计算hash码 -> 经过(n - 1) & hash运算 -> 得出在数组中的下标
1. 构造函数
1.1 无参创建HashMap对象
1.1.1 进入到构造函数中
1.2 有参构造hashmap
1.2.1 进入到构造函数内部
1.2.2 继续调用本类的构造函数
1.2.3 tableSizeFor()函数
调用tableSizeFor函数,这个函数的主要作用就是确定数组的长度,返回的长度是最接近参数的2的N次幂,即当cap=10,返回的是2的4次幂,即16
// 确定主数组的长度,返回的长度是最接近参数的2的N次幂,即当cap=10,返回的是2的4次幂,即16
// cap = 10
static final int tableSizeFor(int cap) {
int n = cap - 1;
// n = 9(00000000 00000000 00000000 00001001)
/*
00000000 00000000 00000000 00001001
>>> 1
==============================================
00000000 00000000 00000000 0000100
00000000 00000000 00000000 00001001
|
00000000 00000000 00000000 00000100
===============================================
00000000 00000000 00000000 00001101 = 13
*/
n |= n >>> 1;
/*
00000000 00000000 00000000 00001101
>>> 2
==============================================
00000000 00000000 00000000 00000011
00000000 00000000 00000000 00001101
|
00000000 00000000 00000000 00000011
===============================================
00000000 00000000 00000000 00001111 = 15
*/
n |= n >>> 2;
/*
00000000 00000000 00000000 00001111
>>> 4
==============================================
00000000 00000000 00000000 00000000
00000000 00000000 00000000 00001111
|
00000000 00000000 00000000 00000000
===============================================
00000000 00000000 00000000 00001111 = 15
*/
n |= n >>> 4;
/*
00000000 00000000 00000000 00001111
>>> 8
==============================================
00000000 00000000 00000000 00000000
00000000 00000000 00000000 00001111
|
00000000 00000000 00000000 00000000
===============================================
00000000 00000000 00000000 00001111 = 15
*/
n |= n >>> 8;
/*
00000000 00000000 00000000 00001111
>>> 16
==============================================
00000000 00000000 00000000 00000000
00000000 00000000 00000000 00001111
|
00000000 00000000 00000000 00000000
===============================================
00000000 00000000 00000000 00001111 = 15
*/
n |= n >>> 16;
// 通过上面的位运算,n的结果为15;
// n=15,三位运算的结果为 n+1,即15+1 = 16
return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
}
此时,有参的hashmap已经创建完成;
2. 添加元素
2.1 第一个元素
2.1.1 进入到put函数中
2.1.2 hash()函数
2.1.3 putVal()函数
2.1.4 进入到resize函数中
resize函数走完,相当于在底层创建了一个长度为16的空数组
继续从第24步往下走
添加完成,数组中有了一个元素
2.2 key值和计算后的hash值都不一样
往map中添加key值和计算后的hash值都不一样的步骤,和第一次添加元素基本一样,直接在对应下标添加数据即可
2.3 key值一样,value不一样
往数组中添加key值一样,value不一样的数据
2.3.1 调用put()
2.3.2 进入putVal()
重新进入到putVal方法中,关键代码
将数组中原有数据的指向p赋值给e后,直接进入到下面代码
2.4 key值不一样,hash值一样
往map中添加key值不一样,但是hash值一样的键值对
假设 “李四” 的hash值与 “张三” 一样
2.4.1 调用put()方法
2.4.2 putVal()方法
再次进入到putVal函数中
2.4.3 treeifyBin 树化操作
3. 总结:
- 元素key唯一;
- 元素无序;
当放入重入key元素时,key是第一个数据的key,value是第二个数据的value;- 放入自定义数据类型时,需要重写hashCode()和equals();
- key值可以存放null;
- hash算法:(n - 1) & hash