链表使用内部类Node来实现的:
数组 链表(散列表) 其实就是用于解决哈希冲突使用的一个拉链法
方法。在数据结构中,我们处理hash冲突常使用的方法有:开发定址法、再哈希法、链地址法、建立公共溢出区。而HashMap中处理hash冲突的方法就是链地址法。
但是这样子的话,如果使用了很久,HashMap存储的元素越来越多,那么链表就会变的很长,那么性能就会下降很多(因为链表不适合查找元素,每次查找元素都要从头开始遍历)。
于是在1.8的时候进行了改进,使用到了红黑树(红黑树是一个自平衡的二叉查找树,查找效率是非常高,时间复杂度仅为O(logN))。
在HashMap中,链表转化成红黑树的条件是当链表长度大于8且数组(桶)的个数要大雨等于64个时,才可以将链表转化成红黑树,它们在源码中的定义如下:
代码语言:javascript复制static final int MIN_TREEIFY_CAPACITY = 64; // 转化成红黑树的最小的桶容量
static final int TREEIFY_THRESHOLD = 8; // 桶上的元素的数量
treeifyBin中的片段:
代码语言:javascript复制// 意思是只要桶的个数小于64个,那么即使桶中的元素个数超过了8个,那么就进行resize扩容,而不是转化成红黑树
if (tab == null || (n = tab.length) < MIN_TREEIFY_CAPACITY)
resize();
putVal中的片段:
代码语言:javascript复制if ((e = p.next) == null) {
p.next = newNode(hash, key, value, null);
// -1 for 1st 可以理解为元素下表从-1开始的,所以可以看作binCount >= 9
if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
treeifyBin(tab, hash);
break;
}
3. HashMap的属性#
代码语言:javascript复制// 默认的初始容量,左移位4位相当于:1*2*2*2*2=16
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4;
代码语言:javascript复制// 最大的容量:2的30次方
static final int MAXIMUM_CAPACITY = 1 << 30;
代码语言:javascript复制// 默认装载因子为0.75
static final float DEFAULT_LOAD_FACTOR = 0.75f;
代码语言:javascript复制// 当一个元素被添加到至少有8个节点的桶中,桶中的链表将会被转化成红黑树,即转化成红黑树条件是大于8个
static final int TREEIFY_THRESHOLD = 8;
代码语言:javascript复制// 红黑树退化成链表的条件:小于等于6时退化
static final int UNTREEIFY_THRESHOLD = 6;
代码语言:javascript复制// 转化成红黑树的最小的桶的数量
static final int MIN_TREEIFY_CAPACITY = 64;