一文搞懂HashMap工作原理和扩容机制(深度对比JDK1.7和JDK1.8)

HashMap简介

  • HashMap基于哈希表的Map接口实现,是以key-value存储形式存在.
  • 系统会根据hash算法来计算key-value的存储位置,可以通过key快速存取value.
  • HashMap使用链表来解决碰撞问题,当发生碰撞了,对象将会储存在链表的下一个节点中。 HashMap在每个链表节点中储存键值对对象。
  • key相同的查找? 因为key本身就是对象, 具有hashcode()和equas()方法, 所以先调用hashcode()方法, 定位到bucket(桶), 然后再调用键对象的equals()方法, 对应的属性.

Entry 数据结构

Entry( int h, K k, V v, Entry<K,V> n) {
        value = v;
        next = n;
        key = k;
        hash = h;
}

HashMap的结构图(1.7) Entry数组+链表

在这里插入图片描述

jdk1.8中废除Entry

jdk1.6中,HashMap中有个内置Entry类,它实现了Map.Entry接口;
jdk1.8中,这个Entry类不见了,变成了Node类,也实现了Map.Entry接口,与jdk1.6中的Entry是等价的。

HashMap的结构图(1.8+) Node数组+链表+红黑树

在这里插入图片描述
当链表长度大于8,Node数组结点转为红黑树

//e是p的下一个节点
if ((e = p.next) == null) {
    //插入链表的尾部
    p.next = newNode(hash, key, value, null);
    //如果插入后链表长度大于8则转化为红黑树
    if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
        treeifyBin(tab, hash);
    break;
}

存储原理

根据上面图片, 我们可以看出, 如果 HashMap 的每个 bucket 里只有一个 Entry 时,HashMap 可以根据索引、快速地取出该 bucket 里的 Entry;在发生“Hash 冲突”的情况下,单个 bucket 里存储的不是一个 Entry,而是一个 Entry 链,系统只能必须按顺序遍历每个 Entry,直到找到想搜索的 Entry 为止——如果恰好要搜索的 Entry 位于该 Entry 链的最末端(该 Entry 是最早放入该 bucket 中),那系统必须循环到最后才能找到该元素。
一句话: put(k,v), 调用hashcode() get(k)调用key.hashcode() 如果冲突有多个, 再调用key.equals(key2);

负载因子和扩容

initailCapacity * loadFactor = HashMap容量
当创建 HashMap 时,有一个默认的负载因子(load factor),其默认值为 0.75,这是时间和空间成本上一种折衷:增大负载因子可以减少 Hash 表(就是那个 Entry 数组)所占用的内存空间,但会增加查询数据的时间开销,而查询是最频繁的的操作(HashMap 的 get() 与 put() 方法都要用到查询);减小负载因子会提高数据查询的性能,但会增加 Hash 表所占用的内存空间。

如果开始就知道 HashMap 会保存多个 key-value 对,可以在创建时就使用较大的初始化容量,如果 HashMap 中 Entry 的数量一直不会超过极限容量(capacity * load factor),HashMap 就无需调用 resize() 方法重新分配 table 数组,从而保证较好的性能。

HashMap的大小很简单,不是实时计算的,而是每次新增加Entry/Node的时候,size就递增。删除的时候就递减。当到达阈值(负载因子*总size)时, 容量翻倍, 并且永远是2^n, 因为hash取模运算太慢, 2^n的容量可以进行位运算

头插尾插?

jdk 1.7 头插
jdk 1.8+ 尾插

因为hashmap在并发resize时会出现的死循环问题, 并且1.7时候用头插是考虑到了一个所谓的热点数据的点(新插入的数据可能会更早用到),但这其实是个伪命题, 因为JDK1.7中rehash的时候,旧链表迁移新链表的时候,如果在新表的数组索引位置相同,则链表元素会倒置(就是因为头插) 所以最后的结果 还是打乱了插入的顺序 所以总的来看支撑1.7使用头插的这点原因也不足以支撑下去了 所以就干脆换成尾插 一举多得

原创文章 280 获赞 464 访问量 10万+

猜你喜欢

转载自blog.csdn.net/qq_33709508/article/details/105503008
今日推荐