一、预备知识
1.HashMap是Map的常用子类
java.util.HashMap<k,v>集合 implements Map<k,v>接口
2.HashMap集合特点
HashMap集合特点
HashMap集合底层是哈希表,查询速度特别快
jdk1.7:数组+单向链表
jdk1.8:数组+单向链表/红黑树(链表长度超过8,数组达到64)
3.HashMap集合是一个无序的集合,存储元素和取出元素的顺序有可能不一致
二、HashMap的底层实现原理
HashMap是Java中的最频繁的一种数据结构
HashMap
底层是一个hash表(数组+链表),这种结构集合了数组和链表的好处。在jdk1.7中,只是单纯的数组+链表的结构,但是如果散列表中的hash碰撞过多时,会造成效率的降低,所以在JDK1.8中对这种情况进行了控制,当一个hash值上的链表长度大于8时,该节点上的数据就不再以链表进行存储,而是转成了一个红黑树
HashMap基于Hash算法实现的
1、当我们往HashMap中put元素时,利用key的hashCode重新hash计算当前对象的元素在数组中的下标
2、存储时,如果出现hash值相同的key,此时有两种情况。
1)如果key相同,则覆盖原始值
2)如果key不同(出现冲突),则将当前的key-value放入链表中
3、获取时,直接找到hash值对应的下标,再进一步判断key是否相同,从而找到对应值。
4、理解以上过程就应当了解了HashMap解决hash冲突的问题,核心就是使用了数组的存储方式,然后将冲突的key的对象放入链表中,一旦发现冲突就在链表中做进一步的对比。
四、HashMap的put与get
put方法
key的hashcode经过高低位异或后的值,然后(table.legth - 1)& hash得到槽位下标
此时有4种情况
1.当槽位(slot)为空,key和value包装为一个node对象,直接存储占用一个solt
2.槽位不为空,判断key是否一样,一样则进行value替换;否则为hash冲突,存入链表中
3.已经链化,和2过程相同,比较存入链表但是判断是否达到了树化的扩容阈值标准
4.红黑树的写入操作
get方法
拿到key算出对应索引
1.根据拿到的索引,映射到对应的hash桶,判断该元素是不是头节点,如果是则直接拿到
2.如果不是头一个节点,用do while循环遍历链表,链表都是next指向下一次拿元素
3.如果是红黑树,由于添加时保证树有序,则利用折半法遍历红黑树
hash冲突:
当我们对某个元素进行哈希运算,得到一个存储地址,然后要进行插入的时候,发现已经被其他元素占用了,这就是所谓的哈希冲突,也叫哈希碰撞
解决方案:开放定址法(找下一个),再散列法,链地址法(HashMap用的)