HashMap底层实现原理解析 阳光穿透心脏的1/2处 2023-10-13 11:03 46阅读 0赞 ![6225b9e118544330a17ef8314bc9e2d0.png][] ### 一、 HashMap中的put()和get()的实现原理: ### #### 1、map.put(k,v)实现原理 #### > * 首先,将k,v封装到Node对象当中(节点)。 > * 然后,它的底层会调用K的hashCode()方法得出hash值。 > * 最后,通过哈希表函数/哈希算法,将hash值转换成数组的下标,下标位置上如果没有任何元素,就把Node添加到这个位置上。如果说下标对应的位置上有链表。此时,就会拿着k和链表上每个节点的k进行equal。如果所有的equals方法返回都是false,那么这个新的节点将被添加到链表的末尾。如其中有一个equals返回了true,那么这个节点的value将会被覆盖。 #### 2、map.get(k)实现原理 #### > * 先调用k的hashCode()方法得出哈希值,并通过哈希算法转换成数组的下标。 > * 通过上一步哈希算法转换成数组的下标之后,在通过数组下标快速定位到某个位置上。如果这个位置上什么都没有,则返回null。如果这个位置上有单向链表,那么它就会拿着K和单向链表上的每一个节点的K进行equals,如果所有equals方法都返回false,则get方法返回null。如果其中一个节点的K和参数K进行equals返回true,那么此时该节点的value就是我们要找的value了,get方法最终返回这个要找的value。 #### 常见问题: #### > * HashMap 增删是在链表上完成的,而查询只需扫描部分,所以随机增删、查询效率都很高 > * HashMap集合的key,会先后调用两个方法,hashCode 和 equals方法,这两个方法都需要重写?因为equals方法默认比较的是两个对象的内存地址 ### 二、HashMap红黑树原理分析 ### 相比 jdk1.7 的 HashMap 而言,jdk1.8最重要的就是引入了红黑树的设计,红黑树除了插入操作慢其他操作都比链表快,当hash表的单一链表长度超过 8 个的时候,数组长度大于64,链表结构就会转为红黑树结构。当红黑树上的节点数量小于6个,会重新把红黑树变成单向链表数据结构。 为什么要这样设计呢?好处就是避免在最极端的情况下链表变得很长很长,在查询的时候,效率会非常慢。 ![6f11b0d18dfa45c5938febeeecf36773.png][] > **红黑树查询:**其访问性能近似于折半查找,时间复杂度 O(logn); > **链表查询:**这种情况下,需要遍历全部元素才行,时间复杂度 O(n); > 简单的说,红黑树是一种近似平衡的二叉查找树,其主要的优点就是“平衡“,即左右子树高度几乎一致,以此来防止树退化为链表,通过这种方式来保障查找的时间复杂度为 log(n)。 ![d31a79d8587e4533af4161bf76184387.png][] 关于红黑树的主要几个特性: > * 每个节点要么是红色,要么是黑色,但根节点永远是黑色的; > * 每个红色节点的两个子节点一定都是黑色; > * 红色节点不能连续(也即是,红色节点的孩子和父亲都不能是红色); > * 从任一节点到其子树中每个叶子节点的路径都包含相同数量的黑色节点; > * 所有的叶节点都是是黑色的(注意这里说叶子节点其实是上图中的 NIL 节点);在树的结构发生改变时(插入或者删除操作),往往会破坏上述条件 3 或条件 4,需要通过调整使得查找树重新满足红黑树的条件。 #### 三、HashMap的原理1.7 和1.8 的区别 #### jdk1.7中底层是由数组+链表实现;jdk1.8中底层是由数组+链表/红黑树实现 可以存储null键和null值,线程不安全 初始size为16,扩容:newsize = oldsize\*2,size一定为2的n次幂 扩容针对整个Map,每次扩容时,原来数组中的元素依次重新计算存放位置,并重新插入 当Map中元素总数超过Entry数组的75%,触发扩容操作,为了减少链表长度,元素分配更均匀 #### 四、hash冲突 #### 当两个key通过hashCod计算相同时(其实hashCode是随机产生的,是有可能hashCode相同),则发生了hash冲突。 **解决hash冲突的方法有:开放定址法、再哈希法、链地址法、建立公共溢出区** HashMap解决hash冲突的方式是用链表。当发生hash冲突时,则将存放在数组中的Entry设置为新值的next,说白就是比如A和B都hash后都映射到下标i中,之前已经有A了,当map.put(B)时,将B放到下标i中,A则为B的next,所以新值存放在数组中,旧值在新值的链表上 **开放定址法:**当关键字key的哈希地址p=H(key)出现冲突时,以p为基础,产生另一个哈希地址p1,如果p1仍然冲突,再以p为基础,产生另一个哈希地址p2,…,直到找出一个不冲突的哈希地址pi ,将相应元素存入其中 **再哈希法:**同时构造多个不同的哈希函数,当哈希地址Hi=RH1(key)发生冲突时,再计算Hi=RH2(key)……,直到冲突不再产生。 **链地址法:**这种方法的基本思想是将所有哈希地址为i的元素构成一个称为同义词链的单链表,并将单链表的头指针存在哈希表的第i个单元中,因而查找、插入和删除主要在同义词链中进行。链地址法适用于经常进行插入和删除的情况。 **建立公共溢出区:**将哈希表分为基本表和溢出表两部分,凡是和基本表发生冲突的元素,一律填入溢出表。 [6225b9e118544330a17ef8314bc9e2d0.png]: https://img-blog.csdnimg.cn/6225b9e118544330a17ef8314bc9e2d0.png [6f11b0d18dfa45c5938febeeecf36773.png]: https://img-blog.csdnimg.cn/6f11b0d18dfa45c5938febeeecf36773.png [d31a79d8587e4533af4161bf76184387.png]: https://img-blog.csdnimg.cn/d31a79d8587e4533af4161bf76184387.png
相关 深入理解hashmap底层实现原理 目录 总体介绍 HashMap元素的存储 在hashmap中添加元素 HashMap的扩容机制 HashMap的线程安全性 1.添加和删除元素时存在不安全性 2. 桃扇骨/ 2024年03月17日 10:05/ 0 赞/ 49 阅读
相关 HashMap底层实现原理解析 ![6225b9e118544330a17ef8314bc9e2d0.png][] 一、 HashMap中的put()和get()的实现原理: 1、map.put(k 阳光穿透心脏的1/2处/ 2023年10月13日 11:03/ 0 赞/ 47 阅读
相关 SpringBoot:SpringBoot 的底层运行原理解析 声明原文出处:狂神说 文章目录 1. pom.xml 1 . 父依赖 旧城等待,/ 2023年09月24日 23:35/ 0 赞/ 53 阅读
相关 CopyOnWriteArrayList底层原理解析 ArrayList并不是一个线程安全的容器,对于高并发下可以用Vector,或者使用Collections的静态方法将ArrayList包装成一个线程安全的类,但是这些方式都是 不念不忘少年蓝@/ 2022年12月28日 08:22/ 0 赞/ 164 阅读
相关 01-Spring底层核心原理解析 Bean查找先根据Bean的类型去(spring容器中-(map))查找,若类型查询不到再根据类型的名称去查找 名称重复会覆盖 --------------- 野性酷女/ 2022年09月10日 08:19/ 0 赞/ 259 阅读
相关 Java HashMap 1.8 底层原理解析 HashMap 原理解析 \ transient:关键字,不去参加序列化操作; 1. HashMap 用于存储数据的,想到底层数据的存储方式,存储数据需要有使 左手的ㄟ右手/ 2022年05月22日 00:12/ 0 赞/ 282 阅读
相关 HashMap底层实现 HashMap发布于jdk1.2,发布HashMap的主要原因在于弥补Hashtable的效率问题,因为Hashtable是同步式实现,所以性能比较差。其实就是优化版Hasht Myth丶恋晨/ 2022年05月15日 03:24/ 0 赞/ 295 阅读
相关 HashMap原理解析 第一:hash定义理解 任意长度的二进制 =====》通过映射规则(哈希算法) ======》固定长度二进制值(哈希值) ![2019072011355773.png][] ╰+攻爆jí腚メ/ 2021年12月01日 11:48/ 0 赞/ 458 阅读
相关 java ArrayList实现原理解析 主要参照jdk1.6,1.7 。 为了便于理解,对源码进行了一定改造,并按层次进行解析。 本文只讨论关键的方法。 主要实现的接口 Iterable:返回一个可迭代 男娘i/ 2021年09月26日 16:56/ 0 赞/ 362 阅读
还没有评论,来说两句吧...