什么事HashMap
HashMap是一种存储双列(key-value)数据结构的集合,进行说明,这种数据结构上提供快存和快取(时间复杂度是1,操作复杂度也是1)
HashMap是什么数据结构组成
JDK1.7版本之前含1.7:数组+链表
JDK1.8之后含1.8:数组+链表+红黑树
进一步细腻的认知:数组是什么东西?
JVM当中连续开辟一组有序的地址存储空间(产生出这样的数据结构)
特点:不可变长度(操作的时候)、类型定义好之后不可变比如 int[] arrays、查找块、增删慢
自动扩容:重新开辟一块更大的数组空间,将原来数组的内容复制到新数组中
HashMap底层是如何实现快速存储的(精髓算法)?
数组结构+链表的形式对提供快速存储和快速取得基本可能。
还有数据的玩法、算法、Hash散列方法+定位算法
Hash算法的应用场景:
进一步解释Hash算法内部的设计
源码我们在map的put方法处打上断点,然后跟进
Integer.valueOf—>put—>hash(key)—>putVal
1 | static final int hash(Object key) { |
Key拿到HashCode再去异或(^,相同为假,相异为假),然后将所取得HashCode三位右移16位(>>>16)
JDK当中确定位置的算法:
index = Hash()(Key的HashCode值的最大散列)——–>返回一个int类型——->转换成二进制 & (数组长度-1)
阿里面试题:为什么JDK底层设计的数组长度为2^n次方?我们的JDK底层源码进行数组扩容也是*2?为什么不是乘以3?
- 数组长度是2^n次方就可以推出——->数组位置的最大编号 index = 2^n-1
- 数组长度是2^n次方—–>这个数可以非常高效的变化:1<<4
- 我们需要将我们Hash()函数返回的hash值与(数组长度-1)进行”与“运算
- 而这个2^n次方-1这个值它的高位都是0,进行“与”运算的时候,它能保证数组下标永远不会越界
注意:这里是”与”运算,就是只有全部为1时才得1,只要有一个为0,则全为0
- 2^n次方-1这个值它的低位都是1,这样当与Hash()函数返回的hash值进行”与”运算时就会尽量散列,减少冲突
- 数组这个位置的利用率提高,保证快速存取
自定义HashMap
1 | package yp.JavaSE.Review_09_容器.myCollection; |
HashMap的put过程
- 首先判断当前HashMap已经使用的大小是否大于(数组长度/扩容因子)
- 如果大于则进行扩容,否则下一步
- 首先根据Key的HashCode方法拿到key的哈希值
- 拿到hash值后通过HashMap中自定义的hash()函数将key的哈希值进行散列如 key >>> 16等
- 将散列后的哈希值和数组(Entry[])长度减1的值进行”与”运算,得到其在数组中的下标
- 判断数组下标处是否有内容,如果没有内容将当前的Entry节点放入即可
- 如果数组下标处有内容,代表这里可能挂了链表,于是将当前Entry节点作为数组此处的首节点,Entry的next指向原来的链表