超详细讲解java中的HashMap,附赠java架构师资料分享
什么是Hashmap
HashMap就是一个容器,用来存储数据,但是为什么不使用Arraylist,或者为什么不使用Link
数组的形式
link的形式
hashMap的形式
看到这里是不是有一种恍然大悟的感觉,hashMap其实就是数组加链表,我最开始的时候问过为什么不使用数组,
数组:使用数组你会发现他查询很快,但是增删改查效率非常低
链表:链表是非常快,但是对于增伤改查非常快,如果查询数组最好,并且链表非常消耗资源
Hashmap:而Hashmap出现就是结合了他们两个的优点※
提问问题
如果你把我下面的问题都会了,那说明你还不错哦,嘿嘿
1为什么使用hashcode?
2为什么会有数组,为什么用链表?
3什么时候扩容,如果进行扩容?
4什么时候使用使用红黑树?
5为什么hashcode要和节点进行与操作?
6数组长度多少,其他空间不可以占用,除非扩容?
7为什么判断hash和可以是否相等?
8整个体系的流程是什么?
代码
一般情况下我们都是这样使用HashMap
源码分析
为什么使用HashCode
你有没有想过一个问题,如果我们使用hashMap,我们的下角标是如何生成的,难道我们使用的是随机数生成的下角标吗?那谁知道数据长度得有多大啊,
- 得到一个节点,重点看hash(key)
2.你会发现hashCode会与做与运行把低16位于高16位进行异或运算,为什么会这么做呢,这么做的时候我们会把前16给取出转换为二进制与h进行异或运算,这样就避免了出现重复的值,如果出现重复的值,可能会出现其中一个链表很长,但是其他位置根本没有数据,所以要把其他的位置都用起来.
下面的操作就是计算node节点到底在数组的什么位置?
n-1 & hash =====>hash%n , 得到的是0-15的区间, n的默认大小是16
0010101011001010010100101001
01111
最终的结果肯定是在16范围之内的.为什么用与是因为&与操作效率比较高
3通过第二步的操作大家有没有感到疑惑,如果是第2步操作得到的是15,那么这个时候二进制变为01110,这个时候不满足16,导致分布不匀均,那么如果才能分布均匀,所以数组的大家都是2的n次幂
在最开始的时候我们就给定默认的值,所以这里的16是有原因的,与操作的时候才会分布均匀
当看到这个的时候你想到了什么,我最开始的时候说要使用hashCode,而hashCode也就是从整个地方过来的,但是你有没有发现当拿到key的hashCode的谁还会进行16位的与操作,为什么在找数组下标(与操作)之前会使用hashCode在进行本身的异或?
原因就是为了避免出现重复的数据,为了node在数组中的位置分布均匀才做的这个操作
让他们两个之间进行异或,得到最后的hashcode
0101001010010高16位
0101001001001低16位
初始化数组
在这里只是声明了数组,但是并没有给数组赋值
赋值语句
把数据放到指定位置
如果是第一次存放
如果是key和hash相等,所以你会发现他到最后返回的以前的value
如果使用红黑树
如果是在链表里
这个时候你会发现他其实就是循环链表,然后判断是否为空
如果这个时候链表的长度超出我们设置的链表长度8-1,那么这个时候就分配红黑树
什么时候扩容
看到这的时候大家有没有疑问,有没有想过数组长度只让用到75%,那么他怎么知道是不是需要扩容呢?
当他的size大于了threshold就会进行扩容,执行resize()操作,最开始我们进行数组初始化的时候也是执行的resize()操作
他首先会判断你是否大于0 ,如果大于0,再判断是否大于最大值
链表可以无限的伸展吗
你有没有想过这个问题? 假如hashmap的其中有一个位一直有node,那么这个时候会无限的向链表中添加数据,那么这个时候链表的数据就会变得很长,所以非常不好, 解决方案是设置规定的值
链表的长度不可以超过8