HashMap

作者: i小雨 | 来源:发表于2021-03-30 00:56 被阅读0次

    成员变量:

    1、序列化版本号:

    private static final long serialVersionUID = 362498820763181265L;
    

    2、集合的初始化容量:(默认为16)

    /**
    * The default initial capacity - MUST be a power of two.
    */
    //默认为16:1<<4(左移4位)相当于1*24次方
    static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
    

    问题1:初始化容量为什么是2的n次幂?如果不为2的n次幂会怎么样?

    当向HashMap中添加元素的时候,需要根据key的hash值去确定其在数组中的位置,HashMap为了存取高效,尽量减少hash碰撞,就需要尽量把数据分配均匀,每个链表(也可能位红黑树)的长度大致相同。这就需要算法:
    这个算法实际上就是取模,hash%length,但是计算机中直接求余的效率不如位运算。所以源码中做了优化,使用:hash&(length-1)按位与,实际上hash%length等于hash&(length-1),前提是length是2的n次幂


    但是为什么这样能够均匀分布减少hash碰撞呢?2的n次幂-1实际上就是n个1.
    比如:
    为2的n次幂:

    图片.png
    不为2的n次幂:
    图片.png

    可以发现:如果数组的长度不是2的n次幂,计算出的索引值很特别容易相同(发生hash碰撞),会导致数组的每个位置下的数据量不均匀,个别位置的链表或者红黑树过长,导致效率降低。


    问题2:当初始化HashMap的时候指定了容量(比如为10),会怎么样?

    HashMap<String,Integer> hashMap = new HashMap<>(10);
    

    根据源码可以发现:如果初始化给的容量不是2的n次幂,最后容量会变成比初始化给定的值大的最小的2的n次幂。
    比如给定的10,将会变成16;给定的17,将会变成32

     public static void main(String[] args) throws Exception {
    
            HashMap<String,Integer> hashMap = new HashMap<>(11);
            Class aClass = hashMap.getClass();
            Method capacity = aClass.getDeclaredMethod("capacity");
            capacity.setAccessible(true);
            System.out.println(capacity.invoke(hashMap));
    
            HashMap<String,Integer> hashMap2 = new HashMap<>(17);
            Class aClass2 = hashMap.getClass();
            Method capacity2 = aClass2.getDeclaredMethod("capacity");
            capacity2.setAccessible(true);
            System.out.println(capacity2.invoke(hashMap2));
    
        }
    ********************************结果:********************************
    16
    32
    

    3、负载因子,默认为0.75:

    static final float DEFAULT_LOAD_FACTOR = 0.75f;
    

    默认容量为16,当容量超过16*0.75=12时会自动扩容

    4、集合最大容量(1<<30)2的30次幂:

    static final int MAXIMUM_CAPACITY = 1 << 30;
    

    5、当链表的的数量超过8,会转为红黑树:(并且数组的长度大于64,也就是参数7)

    static final int TREEIFY_THRESHOLD = 8;
    

    6、当红黑树的数量小于6,会从红黑树转为链表:

    static final int UNTREEIFY_THRESHOLD = 6;
    

    7、链表转为红黑树对应的数组长度的最小值:

    static final int MIN_TREEIFY_CAPACITY = 64;
    

    相关文章

      网友评论

          本文标题:HashMap

          本文链接:https://www.haomeiwen.com/subject/apsswktx.html