HashMap底层原理(jdk1.7和jdk1.8对比)?

news/2024/11/8 9:46:56 标签: 哈希算法, 散列表, 算法

HashMap 底层结构与实现

HashMap 底层是基于哈希表(Hash Table)实现的,它存储的元素是键值对(key-value)。底层的数据结构是一个数组,数组的每个元素是一个 (bucket),用于存储发生哈希碰撞的元素。每个桶本质上是一个链表或红黑树。

1.7 版本(数据结构:数组 + 链表)

JDK 1.7 中,HashMap 底层的哈希表是由数组和链表实现的:

  • 数组:用来存储数据的容器,数组的每个元素是一个桶(bucket)。
  • 链表:当发生哈希冲突时,将多个元素(具有相同哈希值)存储在同一个桶中,链表的形式连接。
1.8 版本(数据结构:数组 + 链表/红黑树)

JDK 1.8 开始,HashMap 进行了优化,链表部分当元素数量大于 8 时会转化为 红黑树,以提高查找性能。新的底层结构为:

  • 数组:依然是用来存储桶。
  • 链表:当桶中的元素较少(<= 8)时,继续使用链表。
  • 红黑树:当桶中的元素较多(> 8)时,链表会转化为红黑树,红黑树的查找时间复杂度是 O(log n),比链表的 O(n) 更高效。

哈希冲突的处理

当发生哈希冲突时(即多个键具有相同的哈希值,经过哈希函数映射到相同的数组索引),HashMap 会通过链表或红黑树来处理冲突。

Java 1.7 中的处理方式:
  • 链表插入:当哈希冲突发生时,新的元素会被添加到 链表的头部。这意味着 HashMap 中的键值对按照插入顺序在链表中排列。

    例如,假设发生冲突的桶索引为 i,原来有一个元素 A(keyA,valueA)在该桶,接着插入一个新元素 B(keyB,valueB)。那么,在 Java 1.7 中,B 会插入到链表的头部,A 会位于链表的后面,形成:

    bucket[i] --> Node(keyB, valueB) -> Node(keyA, valueA)
Java 1.8 中的处理方式:
  • 链表插入:在 Java 1.8 中,哈希冲突时,元素会被插入到 链表的尾部。这意味着新的元素会添加到链表的末尾,而不是头部。

    举个例子,如果桶 i 中原来有元素 A(keyA,valueA),插入 B(keyB,valueB)时,B 会被添加到链表的尾部,形成:

    bucket[i] --> Node(keyA, valueA) -> Node(keyB, valueB)
  • 红黑树转化:当某个桶中的链表长度超过 8 时(默认阈值),链表会转化为红黑树,从而提高查询性能(O(log n)),避免了链表查找的 O(n) 性能瓶颈。

扩容机制

Java 1.7Java 1.8 中,当 HashMap 中的元素数量超过负载因子(默认是 0.75)时,会进行扩容,数组的大小通常会翻倍。扩容时,所有的元素需要重新计算哈希值并重新分配到新的桶中。

总结:Java 1.7 vs Java 1.8 之间的主要区别

  1. 哈希碰撞的处理

    • Java 1.7:哈希冲突发生时,元素插入到链表的头部。
    • Java 1.8:哈希冲突发生时,元素插入到链表的尾部。
  2. 红黑树优化

    • Java 1.7:只有链表来处理哈希冲突。
    • Java 1.8:当某个桶的链表长度大于 8 时,链表会转化为红黑树,以提高查找效率。
  3. 性能优化

    • Java 1.8 在哈希冲突较多的情况下,链表转红黑树的方式能有效提升性能,避免了链表查找的 O(n) 时间复杂度,提升了查询效率。

性能差异

  • 1.7 版本中,当哈希冲突较多时,查找元素的性能会下降,因为冲突处理采用链表,导致最坏情况下需要遍历整个链表(O(n))。
  • 1.8 版本中,当链表长度较长时,链表会被转换为红黑树(O(log n) 查找),大大提升了查询效率。

因此,Java 1.8 对于 HashMap 的性能优化,特别是在冲突较多的情况下,有显著提升。


http://www.niftyadmin.cn/n/5743698.html

相关文章

5G周边知识笔记

这里写目录标题 3GPP 5G标准路径图5G协议规范5G新空口关键指标4G LTE和5G NR新空口技术对比5G新频段FR1FR2 信道带宽上下行解耦新频点规划&#xff0c;信道栅格FR1各频段实际信道栅格和NR-ARFCN范围定义 同步栅格大规模天线阵列新型调制编码技术大规模载波聚合设备到设备直接通…

【GPT使用技巧】用AI出一门课

提问 我想做一个ChatGPT的课程&#xff0c;针对小白&#xff0c;解决从0到1的问题。按照小白的通点&#xff0c;列出大家最关心的问题&#xff0c;做一个课程大纲给我。避免生涩语言&#xff0c;用小白理解和关心的方式展示。 GPT的回答结果 课程大纲&#xff1a;ChatGPT入门…

SPIRE: Semantic Prompt-Driven Image Restoration 论文阅读笔记

这是一篇港科大学生在google research 实习期间发在ECCV2024的语义引导生成式修复的文章&#xff0c;港科大陈启峰也挂了名字。从首页图看效果确实很惊艳&#xff0c;尤其是第三行能用文本调控修复结果牌上的字。不过看起来更倾向于生成&#xff0c;对原图内容并不是很复原&…

C++ | Leetcode C++题解之第546题移除盒子

题目&#xff1a; 题解&#xff1a; class Solution { public:int dp[100][100][100];int removeBoxes(vector<int>& boxes) {memset(dp, 0, sizeof dp);return calculatePoints(boxes, 0, boxes.size() - 1, 0);}int calculatePoints(vector<int>& boxes…

Centos使用yum获取离线安装包

要获取CentOS的yum离线安装包&#xff0c;你可以在有网络连接的环境中下载RPM包及其依赖&#xff0c;然后将它们复制到没有网络的CentOS系统上进行安装。以下是步骤和示例命令&#xff1a; 1、在有网络的环境中&#xff0c;安装yum-utils以便使用yumdownloader工具&#xff1a…

【每日一题】2012考研数据结构 - 求字符串链表公共后缀

本篇文章将为大家讲解一道关于链表的经典题目——求两个链表的共同后缀节点。该问题在实际开发中同样具有很大的应用价值&#xff0c;是每一位数据结构学习者不可错过的重要题目。 问题描述 假设我们有一个带头结点的单链表来保存单词&#xff0c;每个节点包含一个字符和指向…

Flutter自定义矩形进度条实现详解

在Flutter应用开发中&#xff0c;进度条是一个常见的UI组件&#xff0c;用于展示任务的完成进度。本文将详细介绍如何实现一个支持动画效果的自定义矩形进度条。 功能特点 支持圆角矩形外观平滑的动画过渡效果可自定义渐变色可配置边框宽度和颜色支持进度更新动画 实现原理 …

MFC 重写了listControl类(类名为A),并把双击事件的处理函数定义在A中,主窗口如何接收表格是否被双击

刚接触MFC遇到的问题&#xff0c;我在主对话框的.cpp里添加了表格的双击处理事件&#xff0c;但是没用&#xff0c;试了下添加单击的&#xff0c;发现居然可以进单击的处理函数&#xff0c;就很懵逼&#xff0c;然后我就把处理双击事件的函数添加到表格的类中&#xff0c;那这样…