hashmap 初始化参数真的就是你设置多少就是多么吗?
/**
* Returns a power of two size for the given target capacity.
*/
static final int tableSizeFor(int cap) {
int n = cap - 1;
n |= n >>> 1;
n |= n >>> 2;
n |= n >>> 4;
n |= n >>> 8;
n |= n >>> 16;
return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
}
初始值为24,但结果不是24
hash算法
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
为什么会有异或运算呢,是因为只用低8位的话,会出现计算数组index相同的概率变高,所以做异或运算
- 那为什么会概率变高呢?
重点就是在n-1,比如初始化长度位16,16-1的二进制就是 01111,与上面的hash做或运算,计算出结果,如果只是与低位运算的话,比如有A,B两个值,高位不同只是低位相同的话,就会出现计算的结果相同,所以重复的概率变高。
为什么扩容是2倍
看到了吧,是因为位运算 << 1,所以为2倍
为什么加载因子是0.75
传言是黄金比例。
- DEFAULT_INITIAL_CAPACITY: 初始容量,也就是默认会创建 16 个箱子,箱子的个数不能太多或太少。如果太少,很容易触发扩容,如果太多,遍历哈希表会比较慢。
- MAXIMUM_CAPACITY: 哈希表最大容量,一般情况下只要内存够用,哈希表不会出现问题。
- DEFAULT_LOAD_FACTOR: 默认的负载因子。因此初始情况下,当键值对的数量大于 16 * 0.75 = 12 时,就会触发扩容。
- TREEIFY_THRESHOLD: 这个值表示当某个箱子中,链表长度大于 8 时,有可能会转化成树。
- UNTREEIFY_THRESHOLD: 在哈希表扩容时,如果发现链表长度小于 6,则会由树重新退化为链表。
- MIN_TREEIFY_CAPACITY: 在转变成树之前,还会有一次判断,只有键值对数量大于 64 才会发生转换。这是为了避免在哈希表建立初期,多个键值对恰好被放入了同一个链表中而导致不必要的转化。