HashMap源码浅探

2 篇文章 0 订阅

HashMap源码浅探

本文将会持续更新HashMap源码的探秘之旅

底层数据结构

HashMap的底层数据结构主要由一个数组 ,数组元素为Entry链表,当链表元素插入超过8个将转化为红黑树(treeifyBin)。详见以下方法分解。

hash方法

    static final int hash(Object key) {
        int h;
        return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
    }

^ 表示位运算符 异或 ,即 0 1不同为1,相同为0

对象的hashCode存放于对象头的Mark Word中,在64位虚拟机中占 31 bit,如100 0010 0011 1000 1000 0011 1100 0000

HashMap中的hash变量不同于对象的hashCode,而是先调用hashCode()之后,再用hashCode和它的右移16位之后的二进制进行异或操作,为什么要这么做呢?这样做可以让hashCode的所有位都参与运算,后续的确定数组位置的方法是hash再对数组大小取模,同样采用位运算与 & ,index = h & (n - 1),其中n为数组大小,因为数组大小(HashMap容量)总是为2的n次幂,即二进制表示为 0001 0000…,所以2^n -1 二进制为0000 1111 ,和

put方法

作用: put()添加一个键值对到HashMap中

resize 扩容方法

JDK8之前resize方法的多线程下死循环问题:

void resize(int newCapacity) {
	...
	transfer(newTable);//将旧数组中的元素转移到新数组上来
	...
}


QA

Q:为什么HashMap的容量要是2的n次幂 2^n,

A:一 是因为在计算元素的数组索引位置时,使用位运算用hash和容量n-1做逻辑与 ,二 是因为扩容时只要判断新hash高位是否为1(用hash & oldCap == 0判断如 0001 0011 & 0001 0000)因为当容量为2的n次幂时二进制表示为0001 0000···,确定旧链表中元素在新数组中的索引位置newTable[i]是保持不变( 还是增加一个旧容量的大小 newTable[i+oldCap]。

思考 & 举一反三

hashMap中大量运用了位运算符,有时两数之间的运算和判断用位运算性能会更好,因为机器码二进制直接进行运算不用转进制,不过也会带来一定可读性的丢失,还需慎用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值