HashMap的底层原理

HashMap的底层原理:

我们都知道**HashMap**底层是通过数组+链表来实现的,也知道它是不安全的。这里对它对数据的具体存储做些解释。

HashMap开始的存储结构是数组,默认长度为16,如果长度超过了16,会对这个数组进行扩容,默认是2的n次方倍,16过后也就是32,但是又不能让它在17的时候去扩容,这里引入了一个loadFactor,默认是0.75,也就是说当数组的实际值长度超过数组长度 * 0.75时,数组会扩容。这个值为什么不是0.6或者0.8呢,其实是默认的0.75.好像是可以改。。具体也不清楚。
他们存储的过程呢,就是计算key的hash值,通过这个值来判断要存放在数组的哪个位置,读取的时候直接通过数组的下标值进行读取了,但是修改的时候,插入一条或添加一条会影响数组的存储顺序和下标值,这也是为什么数组结构的读取快,增删慢的原因。
计算了key的hash值以后,发现这个值在数组中已经存储过了,这个时候就是hash 冲突,怎么解决呢,我了解的有四种方法:
1):开放地址法。
2):再哈希法。
3):拉链法。
4):建立公共溢出区。
好吧我承认我只会俩。
再哈希法,就是换一个hash算法去计算key值,直到不冲突找到位置为止,比如我们在进行姓名查询的时候,总会出现两个人姓名首字母相同的情况,zs(张三)对应zs(张珊),这时候我们可以换一个算法,对姓名的字母进行查询,zhang是一样的,但是一个san一个shan,这就是不同的值了,我理解的再哈希法大致就是这样。
还有拉链法,如果出现hash冲突了,通过equals方法去计算key值看是否相等,如果计算结果相等,说明是同一个对象,直接进行覆盖,如果不相等,就把这个数组转换为链表的形式进行存储,其中这个新插入的值放在链表头,这就是我理解的拉链法。
JDK1.8以后。hashMap的实现结构变成了数组+链表+红黑树,红黑树我还没有吃透,,,吃透了再过来吹牛皮。
如果要实现安全的hashmap的话,可以使用hashtable,虽然哥们效率8行吧但是安全,还可以用Collections.SynchronizedMap把hashmap包装起来,你说你不安全?哥们有锁。也可以使用ConcurrentHashMap,这哥们我一直理解的是分段锁,就是把一个线程分成多个Segment快,默认是16块,也就是说并发度是16,后期不能修改,其中每一段Segment都可以看成是一个独立的hashmap,每一段都有自己的ReentrantLock锁,在对其中的一段进行操作的时候,其他的也可以看到,并发操作的时候各段互不影响。但是JDK1.8以后,哥们升级了。从Segment变成了Node,每个Node都有自己的锁,每个Node都有自己的并发度,这就提高了开发效率,对比一下,两个版本的区别还是挺大的。
锁:JDK1.7是ReentrantLock锁,JDK1.8是CAS+Synchronized锁
数据结构:JDK1.7是Segment,JDK1.8是Node,由原来的并发度16变成了每个Node都独立,提高了并发度。
hash冲突:JDK1.7对hash冲突采用数组转链表的方式进行操作,JDK1.8聪明了,我就知道你要有hash冲突,我直接使用链表的形式,后面满足条件后我再转换成红黑树,这样也更方便查询。
查询复杂度:JDK1.7中链表的查询复杂度为O(N),JDK1.8中经过红黑树优化变成了O(logN);

差点忘了,JDK1.8中链表长度如果超过8了,就转换为红黑树,如果低于6,就还用链表。
今儿就说到这~~~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值