Java集合之HashMap

概述

HashMap是基于哈希表的Map接口实现的一种存储key、value的数据结构,提供了所有可选的映射操作,且键值允许null的存在,不保证数据映射的顺序,也不能保证顺序在一段时间内保持不变

底层结构

jdk1.7:数组+链表

jdk1.8:数组+链表+红黑树

哈希冲突

从上文图中显而易见,hashMap用的拉链法来解决哈希冲突的,也就是当一个数据计算出来的hash值已经在table数组中存在的话,就以链表的结构追加在后面

  1. 当链表长度>=8且数组长度>=64时,会把链表转化为红黑树
  2. 当链表长度>=8,当数组长度<64时,会优先进行扩容,而不是转化为红黑树
  3. 当红黑树节点数<=6时,自动转化为链表

源码解析

put()

put流程

根据插入数据的key进行hash计算,得到在table数组将要插入的下标索引i,若i号下标为null,则直接插入,若不为null,就要进行「哈希冲突处理」,依次去查找table[i]所挂载的结构数据,也就是遍历链表或红黑树,若key已存在就进行覆盖操作,否则就要找到合适的位置进行插入,链表就是找到尾巴元素,到了尾巴要判断链表和数组的长度看是否要进行扩容或转换结构,若符合条件则先进行扩容或转换结构之后再插入元素

  1. 当链表长度>=8且数组长度>=64时,会把链表转化为红黑树
  2. 当链表长度>=8,当数组长度<64时,会优先进行扩容,而不是转化为红黑树

    public V put(K key, V value) {return putVal(hash(key), key, value, false, true);}final V putVal(int hash, K key, V value, boolean onlyIfAbsent,boolean evict) {Node<K,V>[] tab; Node<K,V> p; int n, i;//判读table是否为空,为空则执行resize()扩容if ((tab = table) == null || (n = tab.length) == 0)n = (tab = resize()).length;//若hash值对应下标的table没有数据,则直接构造node插入if ((p = tab[i = (n - 1) & hash]) == null)tab[i] = newNode(hash, key, value, null);else {Node<K,V> e; K k;//若key已存在,则覆盖原数据if (p.hash == hash &&((k = p.key) == key || (key != null && key.equals(k))))e = p;//若是红黑树,则插入红黑树else if (p instanceof TreeNode)e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);else {//循环遍历链表,查找要插入的位置for (int binCount = 0; ; ++binCount) {//找到了尾巴结点if ((e = p.next) == null) {p.next = newNode(hash, key, value, null);//若链表长度>=8,则进行扩容或转化为红黑树,并插入if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1sttreeifyBin(tab, hash);break;}if (e.hash == hash &&((k = e.key) == key || (key != null && key.equals(k))))break;//插入p = e;}}if (e != null) { // existing mapping for keyV oldValue = e.value;if (!onlyIfAbsent || oldValue == null)e.value = value;afterNodeAccess(e);return oldValue;}}++modCount;if (++size > threshold)resize();afterNodeInsertion(evict);return null;}

resize()扩容

数组长度扩展为原来的两倍,再遍历原的数组,把所有的节点重新hash到新数组中

  1. jdk1.7 :遍历所有的节点,依次通过hash函数计算新的下标,再插入到新数组的链表中。缺点:每个节点都需要进行一次求余计算;插入新数组采用的是头插法,在多线程环境下会形成链表环
  2. jdk1.8:控制数组的长度始终是2的整数次幂,每次扩展数组都是原来的2倍,key在新数组的hash结果只有两种:在原来的位置,或者在原来位置+原数组长度

get()

根据要查找的key计算hash值得到在table数组中的下标索引i,先check table[i]是否为目标值,若是就直接返回,不是就依次查找table[i]挂载的结构中的元素校验是否符合目标值

    public V get(Object key) {Node<K,V> e;return (e = getNode(key)) == null ? null : e.value;}final Node<K,V> getNode(Object key) {Node<K,V>[] tab; Node<K,V> first, e; int n, hash; K k;//check table不为空,根据key计算得到hash值即为在table数据中的下标iif ((tab = table) != null && (n = tab.length) > 0 &&(first = tab[(n - 1) & (hash = hash(key))]) != null) {//若table[i]的key和目标值相同,则找到了if (first.hash == hash && // always check first node((k = first.key) == key || (key != null && key.equals(k))))return first;//遍历桶if ((e = first.next) != null) {//若是红黑树,则通过红黑树算法进行查找if (first instanceof TreeNode)return ((TreeNode<K,V>)first).getTreeNode(hash, key);//遍历链表查找do {if (e.hash == hash &&((k = e.key) == key || (key != null && key.equals(k))))return e;} while ((e = e.next) != null);}}return null;}

常见问题

为什么jdk1.8需要加上红黑树的结构?

首先我们明确了无论是链表还是链表+红黑树都是为了解决哈希冲突的问题,那么从上文的get操作能看到,如果table[i]不是目标元素,就需要依次循环遍历table[i]挂载的结构,挨个对比结点数据是否为目标数据,链表的查询操作的时间复杂度是O(n),所以数据量越大冲突的几率就越大那么查询的效率就越慢,而红黑树的查找时间复杂度是O(logn),加上红黑树就是为了提高查询的速度

线程不安全(Fail-Fast机制)

举例:两个线程同时put,A线程在执行真正的插入操作时时间片到了,A线程挂起,然后B线程进来执行put操作,B线程结束后,A被调度,A的插入操作可能会把B刚刚插入的元素覆盖掉

  1. 如果在使用迭代器的过程中有其他线程修改了map,那么将抛出ConcurrentModificationException,这个结果是通过modCount字段实现的,顾名思义就是修改次数,每次对HashMap的修改都会增加这个值,而在迭代器初始化过程中会将这个值赋给迭代器的expectedModCount
  2. 在迭代过程中,判断modCount跟expectedModCount是否相等,如果不相等就表示已经有其他线程修改了Map

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/704120.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Acrel-1000变电站综合自动化监控系统 实时测控保护、远动于一体

​一、 系统概述 1.1 概述 Acrel-1000 变电站综合自动化监控系统&#xff0c;是我司根据电力系统自动化及无人值守的要求&#xff0c;总结国内外的研究和生产的先进经验&#xff0c;专门研制出的新一代电力监控系统。本系统具有保护、遥测、遥信、遥脉、遥调、遥控功能&#x…

新时代高速数据中心800G DR8光模块解决方案

近年来&#xff0c;随着5G网络、存储介质和计算能力等基础技术的不断升级&#xff0c;100G和400G数据中心得到了普及。如今800G数据中心时代也已经来临。本文将围绕800G DR8来介绍飞速&#xff08;FS&#xff09;800G数据中心解决方案&#xff0c;旨在为全球客户提供全面且高性…

做海外问卷调查有什么方法技巧?

大家好&#xff0c;我是橙河老师&#xff0c;很久没更新文章了&#xff0c;一方面是比较忙&#xff0c;另一方面是觉得关于项目介绍的文章&#xff0c;写的也差不多了。 后面的文章&#xff0c;还是着重讲解不同渠道的特点、做题技巧、人设创建这些实战性的内容。 我不像其他公…

【二叉树】(三)二叉树的基础修改构造及属性求解2

&#xff08;二&#xff09;二叉树的基础修改构造及属性求解2 二叉树的所有路径思路递归法迭代法 左叶子之和递归法迭代法 找树左下角的值递归法迭代法 路径总和从中序与后序遍历序列构造二叉树最大二叉树合并二叉树 二叉树的所有路径 力扣原题链接&#xff1a;257. 二叉树的所…

寄大件家具用什么物流便宜,寄沙发大件物流便宜

在现代生活中&#xff0c;搬家或重新布置家居时&#xff0c;沙发作为体积较大、价值较高的家具&#xff0c;选择一个经济实惠的物流服务至关重要。 1、对于近距离的运输&#xff0c;同城寄沙发可以找个车直接拉过去比较划算&#xff0c;省外的可以试试像我这样邮寄&#xff1b;…

9个优质免费视频素材网站推荐丨2024年最新资源合集

在短视频火爆的时代&#xff0c;高清、无水印、可商用的视频素材变得尤为重要。下面是我精心整理的9个常用免费视频素材网站&#xff0c;适合各类视频创作者。希望你能找到满意的素材&#xff01; 一、视频素材 1. 蛙学府 优点&#xff1a;丰富的正版商用素材&#xff0c;涵盖…

留学资讯 | 2024英国学生签证申请需要满足哪些条件?

英国移民局于2020年9月10日发布了《移民规则变更声明: HC 707》&#xff0c;对学生签证制度进行了全面改革。该法案于2020年10月5日正式生效。根据此法案&#xff0c;新的学生签证——The Student and Child Student Routes学生和儿童学生路线&#xff0c;将替代原先的Tier 4学…

[论文阅读]FINE-TUNE THE PRETRAINED ATST MODEL FOR SOUND EVENT DETECTION

摘要 本研究提出了一种微调预训练模型ATST&#xff08;音频师生转换模型&#xff09;的方法&#xff0c;用于声音事件检测&#xff08;SED&#xff09;。通过引入ATST-Frame模型&#xff0c;该方法在DCASE挑战任务4数据集上取得了新的SOTA结果&#xff0c;有效解决了预训练模型…

Keil手动安装编译器V5版本

V5编译器下载&#xff1a;免积分下载 新版的keil不会自动帮你安装V5版本的编译器&#xff0c;但是很多教程很多比赛所用单片机都是V5的编译器&#xff0c;所以用来开以前的或者开源的很多东西编译直接一大堆报错。 吐槽说完了接下来教你怎么解决 打开installer&#xff08;在…

Hive的排序

order by 全局排序,因此只有一个reducer,设置了多个reducer也不起作用.-- 设置reducer的个数为2 set mapred.reduce.tasks2; -- 查询 select * from user_install_status_limit order by uptime limit 10;order by 在hive.mapred.mode strict 模式下,必须指定 limit,否则执行…

SOLIDWORKS 2024云服务新功能

一、简单的分享一下&#xff0c;在线观看&#xff0c;轻松标记 在达索系统SOLIDWORKS 2024云服务中&#xff0c;您只需在达索系统SOLIDWORKS中点击按钮&#xff0c;就可以将当前的设计分享给其他人&#xff0c;无论是客户、供应商还是团队内部成员。共享的用户只要打开浏览器里…

河南广电与LiblibAI签署战略合作协议

5月15日&#xff0c;河南广电科技与LiblibAI战略签约仪式在郑州中原福塔新闻发布厅隆重举行。双方将本着“共商、共享、共建、共赢”原则&#xff0c;基于全面、可持续的战略合作伙伴关系&#xff0c;发挥各自优势&#xff0c;共同聚焦生成式AI领域&#xff0c;围绕内容创作、商…