hashmap解密个别参数

235 阅读2分钟

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 才会发生转换。这是为了避免在哈希表建立初期,多个键值对恰好被放入了同一个链表中而导致不必要的转化。