认识HashMap

HashMap是我们日常开发中经常用到的一种数据类型,一直没有好好的了解一下它,昨天听了大佬的课,略有收获,记下再说。

HashMap在jdk1.7及以前,他的数据结构为数组加链表,jdk1.8及之后,数据结构为数组+链表+红黑树。

在HashMap存储数据时,通过调用hash(k)的方法计算k的hash值,然后结合数组长度,计算数组下标。

static final int hash(Object key) {
        int h;
        //高16位异或低16位,避免高位不参与下标的计算引起hash冲突
        return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
    }

 

当k的hash值在hashMap中不存在,则执行插入。

当k的hash值存在时,判断两者本身是否值相等,相等则数据覆盖,不等则插入到同一下标。

ps:1.7时为头插法,1.8后为尾插法

1.8后,当同一下标的链表长度为8时,此时单向链表进化为红黑树,当执行删除操作,树的非空节点为6时,退化为单向链表。

选择红黑树的原因是为了解决二叉查找树的缺陷,二叉查找树在特殊情况下会变成一条线性结构,等同于链表,遍历查询效率极低。 而红黑树在插入数据或者删除数据后,会通过左旋、右旋、变色的操作来保持树的平衡,提高查询效率。

static final int TREEIFY_THRESHOLD = 8;

static final int UNTREEIFY_THRESHOLD = 6;

选择8的原因:

理想情况下,在随机哈希代码下,桶中的节点频率遵循
泊松分布,文中给出了桶长度k的频率表。
由频率表可以看出,桶的长度超过8的概率非常非常小。所以作者应该是根据
概率统计而选择了8作为阀值。

    *
     * 0:    0.60653066
     * 1:    0.30326533
     * 2:    0.07581633
     * 3:    0.01263606
     * 4:    0.00157952
     * 5:    0.00015795
     * 6:    0.00001316
     * 7:    0.00000094
     * 8:    0.00000006
     * more: less than 1 in ten million
     *

hashMap默认扩容阈值为0.75,当数组中的数据量达到了数组长度的0.75倍时,数组进行扩容

static final float DEFAULT_LOAD_FACTOR = 0.75f;
static final int MAXIMUM_CAPACITY = 1 << 30;

扩容时、调用resize()方法将数组扩容为原来的2倍,注意,当数组的长度达到2^30(最大值)时,此时数组将不再扩容

扩容时若某个下标下存在长链表,则将长链表下数据重新计算并分配在当前下标或当前下标+扩容前数组长度的下标下。

 

©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页