HashMap
一种经典的kay-value结构的Map,常用于缓存数据,实现在jdk1.8有升级
内部实现:
1.8:底层是数组+链表+红黑树
1.7:底层是数组+链表
核心参数:
DEFAULT_INITIAL_CAPACITY:默认初始化容量,默认值:1<<4
MAXIMUM_CAPACITY:最大容量,默认值:2<<30
DEFAULT_LOAD_FACTOR:默认负载因数,默认值:0.75
MIN_TREEIFY_CAPACITY:最小树容量,默认值:64
TREEIFY_THRESHOLD:树化阈值,默认值:8
UNTREEIFY_THRESHOLD:取消树化阈值,默认值:6
常用方法
put(key, value)
1、判断hash桶是否为空或null,是则resize()初始化
2、根据key的hash值计算出需要放入的位置i,i为空则直接放入,有值则通过hashCode()和equals()判断key是否相等,相等则更新value
3、不等则判断是否为链表,是则检查链表长度是否超过8,超过则转为红黑树再插入,没有则遍历比较key值,看是更新value还是尾插
4、如果是红黑树则比较key值后,看是更新value还是尾插
5、检查hash桶是否需要扩容
如何扩容
提炼后的扩容代码
void resize(int newCapacity) { //传入新的容量
Entry[] oldTable = table; //引用扩容前的Entry数组
int oldCapacity = oldTable.length;
if (oldCapacity == MAXIMUM_CAPACITY) { //扩容前的数组大小如果已经达到最大(2^30)了
threshold = Integer.MAX_VALUE; //修改阈值为int的最大值(2^31-1),这样以后就不会扩容了
return;
}
Entry[] newTable = new Entry[newCapacity]; //初始化一个新的Entry数组
transfer(newTable); //!!将数据转移到新的Entry数组里
table = newTable; //HashMap的table属性引用新的Entry数组
threshold = (int)(newCapacity * loadFactor);//修改阈值
}
void transfer(Entry[] newTable) {
Entry[] src = table; //src引用了旧的Entry数组
int newCapacity = newTable.length;
for (int j = 0; j < src.length; j++) { //遍历旧的Entry数组
Entry<K,V> e = src[j]; //取得旧Entry数组的每个元素
if (e != null) {
src[j] = null;//释放旧Entry数组的对象引用(for循环后,旧的Entry数组不再引用任何对象)
do {
Entry<K,V> next = e.next;
int i = indexFor(e.hash, newCapacity); //!!重新计算每个元素在数组中的位置
e.next = newTable[i]; //标记[1]
newTable[i] = e; //将元素放在数组上
e = next; //访问下一个Entry链上的元素
} while (e != null);
}
}
}
每次扩容2倍
扩容时会重新hash,能有效的打散原链表上的元素

浙公网安备 33010602011771号