HashMap
线程不安全,允许null 值null 键 ,由数组+链表构成
存储原理
有一个数组存储元素,通过hashCode() 来获得关键字的哈希值(实际上是数组的下标)
数组元素:Entry 类型3个数据域(key,value,next)。
存储过程
第一个键值对A进来,通过hashCode()计算其key的hash得到index=0,那么Entry[0]=A, 第二个键值对B的index也等于0,那么B.next=A,Entry[0]=B;如果第三个键值对C的index=0,那么C.next=B,Entry[0]=C 。(使用链表解决哈希冲突)
存 put()
put() ,先hashCode() 计算出在数组中的位置,如果该位置没有Entry 则直接添加进数组,如果有(发生哈希冲突),则先连接上该链表,然后将该Entry 存储上。
取 get()
先hashCode() 计算位置,然后位置没有,则不能取到,否则有一个为取到,有多个即链表,则用equals() 来与关键字比较找出指定项。
HashMap 存的时间复杂度为O(1) ,hashCode() 计算,存到数组,顶多拉一次链接。
取时间复杂度最好为O(1) 没有链表,直接找到,最差为O(n) ,因为要找的值可能在因为哈希冲突而形成的链表里,有可能需要遍历链表,所以最差为O(n) 。
那么HashMap 是如何计算下标的呢
先对key 的hashCode 进行hash 操作,
先将key.hashCode() 的高16 位与低16 位,做了一个异或。
然后进行下标计算,
(n - 1) & hash
扩容
当超过 (当前容量 * 负载因子)时,会进行扩容,扩充为原来的2 倍。
元素的位置要么是在原位置,要么是在原位置再移动2次幂的位置。