HashMap源码还是相对来说好理解一点

世人总是让开发去读源码 这个源码该怎么去读呢?试一下这个hashmap吧。
那就根据使用方法去读。要使用hashMap首先是创建一个HashMap的对象。这个创建就就有这么几种方法:
1,构造方法,首先是 没有参数的构造方法,对应的源码是,
this.loadFactor = DEFAULT_LOAD_FACTOR; 0.75f 负载因子=0.75那么是不是就可以认为这个负载因子很重要,毕竟空参数构造方法都赋值了。
除了没有参数的构造方法之外还有指定初始化容量的构造方法,从这个里面可以看到map的最大容量是 1 左移 30位 即2的30次方。还是挺大的。而这个负载因子是不能小于0可以大于1。

2,put()创建了HashMap之后就需要往里面添加元素,可以说这个put方法是hashmap的精髓,花点时间搞搞也值的。
原来这个方法是有返回值null,put方法调用内部的putVal()方法 该方法有5个参数,除了key,value,还有个 hash(key)的参数,这个地方应该就是取hash值了。
从这个hash(key)方法也能看到 hashMap是支持null的而且null对应的hash值是0。
然后继续putVal()方法,首先上来就是resize方法,因为构造方法只是指定了初始化容量和负载因子其他的都没有初始化。
resize()方法的逻辑就是 先计算数组容量,然后创建一个新数组,把老数组的数据放到新数组里面,
计算数组容量的逻辑是如果之前已经有数据了,那么说明是扩容,扩容的方式是左移一位,扩充为原来的两倍,当然不能超出最大容量。如果之前没有数据,初始化16。
所以初始化就是创建了一个node数组,继续回到putVal()方法,之后根据hash值计算数组下表,直接是 位与运算(n-1)& hash值,如果node数组对应下标的值为空直接放进去。
如果数组对应元素不为空,拿该元素与新元素比较 如果hash相同,并且地址值相同,或者 hash值相同并且equal()为true,就替换元素,这里可以看到先判断地址值,这个效率应该还是高一些。
否则就循环链表或者转化为treeNode,最后size++,如果size大于threshold直接就扩容,所以这个扩容是在put之后做的。
3,get()还是那几个判断条件,hash值相同,地址值相同,或者equals()为true,就认为是同一个元素,找到就返回。

ConcurrentHashMap的源码相对来说难度比较大,还是那句话,功力不够,不能强行搞,容易走火入魔。
ConcurrentHashMap的构造方法什么逻辑也没有,很多属性都是静态的,也就没有构造方法的任务了。
put(),方法也是调用putVal() 上来就是非空校验,key和value都不能为空,大量使用了volatile和compareAndSwap的操作,比如初始化 和数组赋值,如果是操作链表或者红黑树,就是分段锁。

知识点总结: (这里跟着大佬又学到了。)
1,快速计算两倍 i << 1,直接位运算左移一位
2,取模元算 比如i对16取模 就是 i & (16-1)
3,判断奇偶数 x&1==0是偶数 ==1是奇数
4,Unsafe类的使用,首先使用这个类型必须通过bootClassLoader加载才行,我们普通的类都是通过AppClassLoader加载的,因此使用它有技巧,
要么通过 java -Xbootclasspath/a: ${path} // 其中path为调用Unsafe相关方法的类所在jar包路径 这个命令把对应的类或者jar追加到bootstrap路径上,
要么通过反射获取,Unsafe提供的API大致可分为内存操作、CAS、Class相关、对象操作、线程调度、系统信息获取、内存屏障、数组操作等几类目前我的功力只能到这一步
强行理解容易吐血,之后再继续吧。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

lx18854869896

和谐社会靠你了,老铁...

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值