当前位置: 首页 > wzjs >正文

重庆食品商城网站设计网站开发实用技术介绍

重庆食品商城网站设计,网站开发实用技术介绍,陕西住房和城乡建设厅网站6,提高自己的网站常见集合篇(五):深入解析 HashMap,从原理到源码,全方位解读 常见集合篇(五):深入解析 HashMap,从原理到源码,全方位解读引言一、HashMap 的实现原理1.1 数据结构基础1.2 存储逻辑示例 二、HashMap 的 put 方…

常见集合篇(五):深入解析 HashMap,从原理到源码,全方位解读

  • 常见集合篇(五):深入解析 HashMap,从原理到源码,全方位解读
    • 引言
    • 一、HashMap 的实现原理
      • 1.1 数据结构基础
      • 1.2 存储逻辑示例
    • 二、HashMap 的 `put` 方法具体流程
      • 2.1 JDK 8 源码分析
      • 2.2 执行步骤拆解
    • 三、HashMap 常见属性
    • 四、HashMap 的扩容机制
      • 4.1 触发条件
      • 4.2 扩容过程
      • 4.3 示例
    • 五、HashMap 的寻址算法
      • 5.1 哈希计算
      • 5.2 桶定位
    • 六、HashMap 在 1.7 下的多线程死循环问题
      • 6.1 问题根源
      • 6.2 示例场景
    • 七、HashSet 与 HashMap 的区别
    • 八、HashTable 与 HashMap 的区别
    • 总结

常见集合篇(五):深入解析 HashMap,从原理到源码,全方位解读

引言

在 Java 编程领域,HashMap 是一种高频使用的数据结构,无论是日常开发中的键值对存储,还是面试中的核心考点,它都占据着重要地位。本文将围绕 HashMap 的实现原理、put 方法流程、常见属性、扩容机制、寻址算法等核心问题展开深度剖析,同时对比 HashSet、HashTable 的差异,帮助读者全面掌握这一关键数据结构。


一、HashMap 的实现原理

1.1 数据结构基础

HashMap 采用 “数组 + 链表 + 红黑树” 的复合结构:

  • 数组:作为底层存储,每个数组元素称为一个“桶”(Bucket)。

  • 链表:当多个键值对的哈希值映射到同一桶时,通过链表解决冲突。

  • 红黑树:当链表长度超过阈值(默认 8),链表会转为红黑树,提升查询效率(JDK 8 新增优化)。

  • 冲突处理:由于不同的键可能具有相同的哈希值,这就会导致冲突。当发生冲突时,HashMap使用链表或红黑树等数据结构来存储具有相同哈希值的键值对。这些数据结构允许在冲突的位置上存储多个键值对,并通过比较键的equals()方法来区分它们

    链表:在JDK 8之前,HashMap使用链表来解决冲突。当多个键值对被映射到同一个桶时,它们会形成一个链表。通过遍历链表来查找、插入或删除键值对。但是,当链表长度过长时,会影响HashMap的性能

    红黑树:从JDK 8开始,当链表长度超过一个阈值(默认为8)时,链表会被自动转换为红黑树,以提高操作效率。红黑树的查找、插入和删除操作具有较低的时间复杂度,可以在平均情况下保持对数时间复杂度

1.2 存储逻辑示例

假设存储键值对 {“key1”, “value1”}

  1. 计算 key1 的哈希值,确定其在数组中的桶位置。
  2. 若桶为空,直接将键值对存入桶对应的链表头。
  3. 若桶已存在元素,遍历链表(或红黑树),对比键是否相等:
    • 相等则覆盖值;
    • 不相等则新增节点(若链表长度达标,转换为红黑树)。

二、HashMap 的 put 方法具体流程

2.1 JDK 8 源码分析

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;// 1. 初始化数组if ((tab = table) == null || (n = tab.length) == 0)n = (tab = resize()).length;// 2. 定位桶,若桶空则新建节点if ((p = tab[i = (n - 1) & hash]) == null)tab[i] = newNode(hash, key, value, null);else {Node<K,V> e; K k;// 3. 桶首节点匹配if (p.hash == hash && ((k = p.key) == key || (key != null && key.equals(k))))e = p;// 4. 红黑树处理else if (p instanceof TreeNode)e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);else {// 5. 遍历链表for (int binCount = 0; ; ++binCount) {if ((e = p.next) == null) {p.next = newNode(hash, key, value, null);// 链表转红黑树if (binCount >= TREEIFY_THRESHOLD - 1) treeifyBin(tab, hash);break;}// 找到重复键if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k))))break;p = e;}}if (e != null) { // 覆盖值V oldValue = e.value;if (!onlyIfAbsent || oldValue == null)e.value = value;return oldValue;}}++modCount;// 6. 检查扩容if (++size > threshold)resize();return null;
}

2.2 执行步骤拆解

  1. 计算哈希:通过 hash(key) 对键进行哈希处理,减少哈希冲突。
  2. 初始化数组:若数组未初始化,调用 resize() 创建默认容量(16)的数组。
  3. 定位桶位置:通过 (n - 1) & hash 计算桶索引。
  4. 处理冲突
    • 桶为空:直接插入新节点。
    • 桶非空:检查桶首节点是否匹配,匹配则覆盖值;若为红黑树,调用红黑树插入方法;否则遍历链表,插入新节点(若链表过长,转换为红黑树)。
  5. 检查扩容:若元素数量超过阈值,触发扩容。

三、HashMap 常见属性

属性名称类型默认值说明
DEFAULT_INITIAL_CAPACITYint16默认初始容量,必须是 2 的幂次。
DEFAULT_LOAD_FACTORfloat0.75f默认负载因子,用于计算扩容阈值。
thresholdint-扩容阈值,值为 容量 × 负载因子
loadFactorfloat-负载因子,控制扩容时机,影响空间和时间效率。
modCountint-记录集合结构修改次数,用于 ConcurrentModificationException 快速失败机制。

四、HashMap 的扩容机制

4.1 触发条件

size(当前元素数量)超过 threshold(扩容阈值,即 容量 × 负载因子)时,触发扩容。

4.2 扩容过程

  1. 创建新数组:新数组容量为旧数组的 2 倍,例如旧容量 16,新容量 32。
  2. 迁移元素:遍历旧数组每个桶,重新计算元素在新数组的位置并复制。由于容量是 2 的幂次,元素新位置要么在原位置,要么在原位置 + 旧容量。

4.3 示例

假设初始容量为 16,负载因子 0.75,阈值为 12。当添加第 13 个元素时:

  1. 触发扩容,创建容量为 32 的新数组。
  2. 遍历旧数组,每个元素重新计算哈希:
    • 若元素原桶索引为 i,新索引可能是 ii + 16
    • 例如,旧数组中某元素哈希值与 15(16-1)按位与得 5,扩容后与 31(32-1)按位与,若高位变化,新索引为 5 + 16 = 21。

五、HashMap 的寻址算法

5.1 哈希计算

static final int hash(Object key) {int h;return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
  • 目的:将哈希码的高 16 位与低 16 位异或,减少哈希冲突。
  • 示例:若 key.hashCode()0b10101100,右移 16 位后与原值异或,混合高低位信息。

5.2 桶定位

通过 (n - 1) & hash 计算桶索引,其中 n 是数组长度(且为 2 的幂次)。例如,数组长度 16(二进制 10000),n - 11501111),与哈希值按位与,确保结果在数组范围内,且分布均匀。


六、HashMap 在 1.7 下的多线程死循环问题

6.1 问题根源

JDK 1.7 中,HashMap 扩容采用头插法。多线程环境下,若线程 A 和线程 B 同时扩容,可能导致链表节点顺序混乱,形成循环链表。

6.2 示例场景

  1. 初始链表:节点 AB,存储在旧数组桶中。
  2. 线程 A 扩容:复制 B 到新数组,再复制 A,新链表为 AB
  3. 线程 B 同时扩容:同样复制节点,但因并发操作,链表可能变为 ABA,形成循环。
  4. 查询触发死循环:遍历链表时,因循环结构导致无限循环。

七、HashSet 与 HashMap 的区别

对比维度HashSetHashMap
存储内容仅存储键,值为固定对象 PRESENT存储键值对
实现原理基于 HashMap,复用 HashMap 的键存储逻辑独立实现键值对存储
核心方法add()remove() 等键操作put()get() 等键值对操作
空值支持允许存储一个 null允许 null 键和 null 值(键唯一)

示例

HashSet<String> set = new HashSet<>();
set.add("test"); // 内部调用 HashMap 的 put(key, PRESENT)HashMap<String, Integer> map = new HashMap<>();
map.put("key", 1); // 存储键值对

八、HashTable 与 HashMap 的区别

对比维度HashTableHashMap
线程安全方法加 synchronized,线程安全非线程安全
空值支持键和值均不能为 null允许 null 键和 null 值(键唯一)
性能同步开销大,性能较低无同步开销,性能更优
继承体系继承 Dictionary实现 Map 接口
扩容机制扩容为原容量 2 倍 + 1扩容为原容量 2 倍

示例

HashTable<String, Integer> table = new HashTable<>();
// table.put(null, 1); // 编译报错,不允许 null 键
// table.get(null); // 编译报错,不允许 null 键HashMap<String, Integer> map = new HashMap<>();
map.put(null, 1); // 允许 null 键
map.put("key", null); // 允许 null 值

总结

通过对 HashMap 实现原理、put 流程、属性、扩容机制、寻址算法的深入分析,以及与 HashSet、HashTable 的对比,我们全面掌握了这一数据结构的核心要点。在实际开发中,需根据场景选择合适的集合:单线程环境优先用 HashMap;需要线程安全时,可选择同步包装类 Collections.synchronizedMapConcurrentHashMap;而 HashTable 因性能问题已逐渐被替代。理解这些细节,不仅能写出更高效的代码,也能在面试中从容应对相关问题。


文章转载自:

http://16UfVEGE.tdxLj.cn
http://ZMXuoFJ1.tdxLj.cn
http://3nUwXDqA.tdxLj.cn
http://Ylp5THxv.tdxLj.cn
http://1SSVtzZW.tdxLj.cn
http://QAJruPbw.tdxLj.cn
http://IAay49Oj.tdxLj.cn
http://sWcEZD1m.tdxLj.cn
http://b5mba6iR.tdxLj.cn
http://PDM1d0OF.tdxLj.cn
http://KzfnZ1fv.tdxLj.cn
http://Rq5xTRGk.tdxLj.cn
http://1yRA9kYY.tdxLj.cn
http://AlHxI5Y2.tdxLj.cn
http://Yl7tJwWr.tdxLj.cn
http://9lmWB9j5.tdxLj.cn
http://nX46byiO.tdxLj.cn
http://2o36QanY.tdxLj.cn
http://rjP13F0K.tdxLj.cn
http://uWL9n4ZN.tdxLj.cn
http://Vv3GPwBx.tdxLj.cn
http://wY9IHEHw.tdxLj.cn
http://oLRqEIp8.tdxLj.cn
http://j2nHykyQ.tdxLj.cn
http://DoOGtP8o.tdxLj.cn
http://HWzRwhaD.tdxLj.cn
http://uy1WSyBT.tdxLj.cn
http://USFTxVkf.tdxLj.cn
http://sG9EVaUS.tdxLj.cn
http://mkn4W84Y.tdxLj.cn
http://www.dtcms.com/wzjs/622317.html

相关文章:

  • 网站建设沈阳下载莱芜都市网app
  • 做菠菜网站判多久网站建设公司 云智互联
  • 云南高端网站制作价格wordpress 采集 api
  • 那个网站报道过鸟巢建设无锡网红餐厅
  • gulf oil wordpress镇江网站seo
  • 精品设计网站crm系统是什么
  • 吉林省长春市建设局网站wordpress换轮播海报
  • 网站建设及运维方案截图京东图片做网站
  • 张家界做网站找哪家好百度推广需要备案的网站吗
  • 怎么自己注册网站中山seo建站
  • 网站推广服务合同如何建立wordpress商城
  • 门户网站的主要特点网站空间会过期吗
  • 阿里巴巴网站服务内容网站制作什么样的字体好看
  • 做视频网站是什么职业村级网站建站
  • 东莞网站建设市场购物网站的建设与维护
  • 泰州市住房和城乡建设局网站网站文章更新
  • 九江网站建设优化哪个网站是做韩国化妆品正品
  • 网站技术解决方案不包括哈尔滨建站费用
  • 兰州建设网站的网站东莞电子网站建设
  • 四川城乡建设官方网站做自己的网站需要多少钱
  • wordpress清理英文站 wordpress seo优化
  • wordpress 全站pjax铜仁做网站的公司
  • 胶州网站建设公司怎做不下网站刷枪
  • vs2015网站开发网页设计需要学什么书
  • 公司做的网站费用如何做账淘宝店需要多少资金
  • 谷城网站开发网站建设有哪些功能模块
  • html5 个人网站模板昆明做网站做的好的公司
  • 用动态和静态设计一个网站网站统计 wordpress
  • 网站制作专业的公司wordpress福利
  • 柳州网站建设找华仔公司网站友情链接