首页 > 其他分享 >HashMap

HashMap

时间:2023-09-10 23:23:52浏览次数:52  
标签:HashMap 元素 数组 链表 key put

1.数据结构

HashMap 主要用来存放键值对,它基于哈希表的 Map 接口实现,是常用的 Java 集合之一,是非线程安全的。

HashMap 可以存储 null 的 key 和 value,但 null 作为键只能有一个,null 作为值可以有多个

JDK1.8 之前 HashMap 由 数组+链表 组成的,数组是 HashMap 的主体,链表则是主要为了解决哈希冲突而存在的(“拉链法”解决冲突)。 JDK1.8 以后的 HashMap 在解决哈希冲突时有了较大的变化,当链表长度大于等于阈值(默认为 8)(将链表转换成红黑树前会判断,如果当前数组的长度小于 64,那么会选择先进行数组扩容,而不是转换为红黑树)时,将链表转化为红黑树,以减少搜索时间。

HashMap 默认的初始化大小为 16。之后每次扩充,容量变为原来的 2 倍。并且, HashMap 总是使用 2 的幂作为哈希表的大小。

2.负载因子

loadFactor 负载因子是控制数组存放数据的疏密程度,loadFactor 越趋近于 1,那么 数组中存放的数据(entry)也就越多,也就越密,也就是会让链表的长度增加,loadFactor 越小,也就是趋近于 0,数组中存放的数据(entry)也就越少,也就越稀疏。

loadFactor 太大导致查找元素效率低,太小导致数组的利用率低,存放的数据会很分散。loadFactor 的默认值为 0.75f 是官方给出的一个比较好的临界值

给定的默认容量为 16,负载因子为 0.75。Map 在使用过程中不断的往里面存放数据,当数量超过了 16 * 0.75 = 12 就需要将当前 16 的容量进行扩容,而扩容这个过程涉及到 rehash、复制数据等操作,所以非常消耗性能。


3.增加元素

put 方法

HashMap 只提供了 put 用于添加元素,putVal 方法只是给 put 方法调用的一个方法,并没有提供给用户使用。

对 putVal 方法添加元素的分析如下:

  1. 如果定位到的数组位置没有元素 就直接插入。

  2. 如果定位到的数组位置有元素就和要插入的 key 比较,如果 key 相同就直接覆盖,如果 key 不相同,就判断 p 是否是一个树节点,如果是就调用e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value)将元素添加进入。如果不是就遍历链表插入(插入的是链表尾部)。


我们再来对比一下 JDK1.7 put 方法的代码

对于 put 方法的分析如下:

  • ① 如果定位到的数组位置没有元素 就直接插入。

  • ② 如果定位到的数组位置有元素,遍历以这个元素为头结点的链表,依次和插入的 key 比较,如果 key 相同就直接覆盖,不同就采用头插法插入元素。


hashmap之前是使用头插法,后来改为尾插法,是因为头插法在多线程情况下会产生环形链表

4.线程安全

put是不安全的,get是安全

标签:HashMap,元素,数组,链表,key,put
From: https://www.cnblogs.com/gaojinhang/p/17692263.html

相关文章

  • HashMap的底层原理
    HashMap哈希表(HashTable)是一种用于存储键值对的数据结构,他的底层实现在jdk1.8后是数组+链表+红黑树,在jdk1.8前是数组+链表,他通过哈希函数将键映射到储存桶中,从而实现快速的插入,查找和删除操作。哈希表的实现通常包括一个数组和一个哈希函数,其中数组用于储存键值对,哈希函数将建映......
  • hashmap头插法和尾插法区别
    前言HashMap应该算是Java后端工程师面试的必问题,因为其中的知识点太多,很适合用来考察面试者的Java基础。开场面试官:你先自我介绍一下吧!安琪拉:我是安琪拉,草丛三婊之一,最强中单(钟馗不服)!哦,不对,串场了,我是**,目前在--公司做--系统开发。面试官:看你简历上写熟悉Java集合,Hash......
  • hashMap产生的循环依赖问题
    转:hashMap产生的循环依赖问题 这样就是一个很经典hashMap线程不安全导致的循环依赖,因为是个循环链表,就会导致数组一直重复扩容,导致集合的一个无限大,但是JDK1.8的时候,把头插法改成了尾插法,同时引进了红黑树,当连续扩容32次的时候会转换成红黑树,解决这个循环依赖的问题,但是还是......
  • HashMap、LinkedHashMap和TreeMap:你真的了解它们吗?
    亲爱的小伙伴们,大家好呀!我是小米,一个热衷于技术分享的90后程序员。今天我要和大家聊聊一个在面试中经常会被问到的话题:HashMap、LinkedHashMap、TreeMap的区别。这可是一个非常重要的知识点,不仅在面试中会被频繁提及,而且在实际开发中也经常用到。让我们一起深入了解这三者的异同吧!H......
  • HashMap的put方法
    HashMap结构简略图调用put()函数,如果table为空,则说明调用HashMap的无参构造函数并且第一次调用put函数,putVal内部调用resize()函数设置容量和阈值分别为16和12;(n-1)&hash进行取模计算下标,n是2的次幂,则n-1的有效位全为1,方便快速计算publicVput(Kkey,Vvalue){......
  • 文盘Rust -- 生命周期问题引发的 static hashmap 锁
    2021年上半年,撸了个rustcli开发的框架,基本上把交互模式,子命令提示这些cli该有的常用功能做进去了。项目地址:https://github.com/jiashiwen/interactcli-rs。春节以前看到axum已经0.4.x了,于是想看看能不能用rust做个服务端的框架。春节后开始动手,在做的过程中会碰到各种有趣的问......
  • 文盘Rust -- 生命周期问题引发的 static hashmap 锁 | 京东云技术团队
    2021年上半年,撸了个rustcli开发的框架,基本上把交互模式,子命令提示这些cli该有的常用功能做进去了。项目地址:https://github.com/jiashiwen/interactcli-rs。春节以前看到axum已经0.4.x了,于是想看看能不能用rust做个服务端的框架。春节后开始动手,在做的过程中会碰到各种有趣的问题......
  • HashMap遍历方式
    HashMap是一个键值对的集合,我们不能通过简单的循环来遍历HashMap,所以我们一般通过以下两种方式来遍历HashMap,一种是通过KeySet集合来遍历,另一种是通过entry键值对对象来遍历。KeySet遍历HashMap通过keySet()方法获取HashMap的keySet集合遍历keySet集合,可以使用iterator迭代器或......
  • HashMap线程安全(含答案)
    HashMap线程安全(含答案)Java中平时用的最多的Map集合就是HashMap了,它是线程不安全的。看下面两个场景:1、当用在方法内的局部变量时,局部变量属于当前线程级别的变量,其他线程访问不了,所以这时也不存在线程安全不安全的问题了。2、当用在单例对象成员变量的时候呢?这时候多个线程过来访......
  • HashMap线程安全面试题(含答案)
    HashMap线程安全面试题(含答案)Java中平时用的最多的Map集合就是HashMap了,它是线程不安全的。看下面两个场景:1、当用在方法内的局部变量时,局部变量属于当前线程级别的变量,其他线程访问不了,所以这时也不存在线程安全不安全的问题了。2、当用在单例对象成员变量的时候呢?这时候多个线......