热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

面试题:说说HashMap的扩容过程?

这是一道阿里的面试题,考察你对HashMap源码的了解情况,废话不多说,咱们就直接上源码吧!jdk1.7源码voidre

  这是一道阿里的面试题,考察你对HashMap源码的了解情况,废话不多说,咱们就直接上源码吧!


jdk 1.7 源码

void resize(int newCapacity) {Entry[] oldTable = table;//保存旧数组int oldCapacity = oldTable.length;if (oldCapacity == MAXIMUM_CAPACITY) {//判断当前数组大小是否达到最大值threshold = Integer.MAX_VALUE;return;}Entry[] newTable = new Entry[newCapacity];//创建一个新数组boolean oldAltHashing = useAltHashing;useAltHashing |= sun.misc.VM.isBooted() &&(newCapacity >= Holder.ALTERNATIVE_HASHING_THRESHOLD);boolean rehash = oldAltHashing ^ useAltHashing;//是否需要重新计算hash值transfer(newTable, rehash);//将oldTable的元素迁移到newTabletable = newTable;//将新数组重新赋值//重新计算阈值threshold = (int)Math.min(newCapacity * loadFactor, MAXIMUM_CAPACITY + 1);
}
void transfer(Entry[] newTable, boolean rehash) {int newCapacity &#61; newTable.length;for (Entry<K,V> e : table) {//遍历oldTable迁移元素到newTablewhile(null !&#61; e) {//①处会导致闭环&#xff0c;从而导致e永远不为空&#xff0c;然后死循环&#xff0c;内存直接爆了Entry<K,V> next &#61; e.next;if (rehash) {//是否需要重新计算hash值e.hash &#61; null &#61;&#61; e.key ? 0 : hash(e.key);}int i &#61; indexFor(e.hash, newCapacity);e.next &#61; newTable[i];//①newTable[i] &#61; e;//①e &#61; next;//①}}
}

jdk 1.8 源码(比较长&#xff0c;慢慢品哈)

final Node<K,V>[] resize() {Node<K,V>[] oldTab &#61; table;//保存旧数组int oldCap &#61; (oldTab &#61;&#61; null) ? 0 : oldTab.length;int oldThr &#61; threshold;//保存旧阈值int newCap, newThr &#61; 0;//创建新的数组大小、新的阈值if (oldCap > 0) {if (oldCap >&#61; MAXIMUM_CAPACITY) {//判断当前数组大小是否达到最大值threshold &#61; Integer.MAX_VALUE;return oldTab;}else if ((newCap &#61; oldCap << 1) < MAXIMUM_CAPACITY &&oldCap >&#61; DEFAULT_INITIAL_CAPACITY)newThr &#61; oldThr << 1; //扩容两倍的阈值}else if (oldThr > 0) // 初始化新的数组大小newCap &#61; oldThr;else {//上面条件都不满足&#xff0c;则使用默认值newCap &#61; DEFAULT_INITIAL_CAPACITY;newThr &#61; (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);}if (newThr &#61;&#61; 0) {//初始化新的阈值float ft &#61; (float)newCap * loadFactor;newThr &#61; (newCap < MAXIMUM_CAPACITY && ft < (float)MAXIMUM_CAPACITY ?(int)ft : Integer.MAX_VALUE);}threshold &#61; newThr;//将新阈值赋值到当前对象&#64;SuppressWarnings({"rawtypes","unchecked"})//创建一个newCap大小的数组NodeNode<K,V>[] newTab &#61; (Node<K,V>[])new Node[newCap];table &#61; newTab;if (oldTab !&#61; null) {for (int j &#61; 0; j < oldCap; &#43;&#43;j) {//遍历旧的数组Node<K,V> e;if ((e &#61; oldTab[j]) !&#61; null) {oldTab[j] &#61; null;//释放空间if (e.next &#61;&#61; null)//如果旧数组中e后面没有元素&#xff0c;则直接计算新数组的位置存放newTab[e.hash & (newCap - 1)] &#61; e;else if (e instanceof TreeNode)//如果是红黑树则单独处理((TreeNode<K,V>)e).split(this, newTab, j, oldCap);else { //链表结构逻辑&#xff0c;解决hash冲突Node<K,V> loHead &#61; null, loTail &#61; null;Node<K,V> hiHead &#61; null, hiTail &#61; null;Node<K,V> next;do {next &#61; e.next;if ((e.hash & oldCap) &#61;&#61; 0) {if (loTail &#61;&#61; null)loHead &#61; e;elseloTail.next &#61; e;loTail &#61; e;}else {if (hiTail &#61;&#61; null)hiHead &#61; e;elsehiTail.next &#61; e;hiTail &#61; e;}} while ((e &#61; next) !&#61; null);//原索引放入数组中if (loTail !&#61; null) {loTail.next &#61; null;newTab[j] &#61; loHead;}//原索引&#43;oldCap放入数组中if (hiTail !&#61; null) {hiTail.next &#61; null;newTab[j &#43; oldCap] &#61; hiHead;//jdk1.8优化的点}}}}}return newTab;}

总结

  jdk1.7扩容是重新计算hash&#xff1b;jdk1.8是要看看原来的hash值新增的那个bit是1还是0好了&#xff0c;如果是0则索引没变&#xff0c;如果是1则索引变成"原索引&#43;oldCap".这是jdk1.8的亮点&#xff0c;设计的确实非常的巧妙&#xff0c;即省去了重新计算hash值得时间&#xff0c;又均匀的把之前的冲突的节点分散到新的数组bucket上

  jdk1.7在rehash的时候&#xff0c;旧链表迁移到新链表的时候&#xff0c;如果在新表的数组索引位置相同&#xff0c;则链表元素会倒置&#xff0c;但是jdk1.8不会倒置


推荐阅读
  • 本题探讨了在大数据结构背景下,如何通过整体二分和CDQ分治等高级算法优化处理复杂的时间序列问题。题目设定包括节点数量、查询次数和权重限制,并详细分析了解决方案中的关键步骤。 ... [详细]
  • PHP 实现多级树形结构:构建无限层级分类系统
    在众多管理系统中,如菜单、分类和部门等模块,通常需要处理层级结构。为了高效管理和展示这些层级数据,本文将介绍如何使用 PHP 实现多级树形结构,并提供代码示例以帮助开发者轻松实现无限分级。 ... [详细]
  • 在高并发需求的C++项目中,我们最初选择了JsonCpp进行JSON解析和序列化。然而,在处理大数据量时,JsonCpp频繁抛出异常,尤其是在多线程环境下问题更为突出。通过分析发现,旧版本的JsonCpp存在多线程安全性和性能瓶颈。经过评估,我们最终选择了RapidJSON作为替代方案,并实现了显著的性能提升。 ... [详细]
  • ElasticSearch 集群监控与优化
    本文详细介绍了如何有效地监控 ElasticSearch 集群,涵盖了关键性能指标、集群健康状况、统计信息以及内存和垃圾回收的监控方法。 ... [详细]
  • 由二叉树到贪心算法
    二叉树很重要树是数据结构中的重中之重,尤其以各类二叉树为学习的难点。单就面试而言,在 ... [详细]
  • 目录一、salt-job管理#job存放数据目录#缓存时间设置#Others二、returns模块配置job数据入库#配置returns返回值信息#mysql安全设置#创建模块相关 ... [详细]
  • 本文介绍 SQL Server 的基本概念和操作,涵盖系统数据库、常用数据类型、表的创建及增删改查等基础操作。通过实例帮助读者快速上手 SQL Server 数据库管理。 ... [详细]
  • 2018-2019学年第六周《Java数据结构与算法》学习总结
    本文总结了2018-2019学年第六周在《Java数据结构与算法》课程中的学习内容,重点介绍了非线性数据结构——树的相关知识及其应用。 ... [详细]
  • 深入解析Java枚举及其高级特性
    本文详细介绍了Java枚举的概念、语法、使用规则和应用场景,并探讨了其在实际编程中的高级应用。所有相关内容已收录于GitHub仓库[JavaLearningmanual](https://github.com/Ziphtracks/JavaLearningmanual),欢迎Star并持续关注。 ... [详细]
  • 在 Android 开发中,通过 Intent 启动 Activity 或 Service 时,可以使用 putExtra 方法传递数据。接收方可以通过 getIntent().getExtras() 获取这些数据。本文将介绍如何使用 RoboGuice 框架简化这一过程,特别是 @InjectExtra 注解的使用。 ... [详细]
  • 如何使用Ping命令来测试网络连接?当网卡安装和有关参数配置完成后,可以使用ping命令来测试一下网络是否连接成功。以winXP为例1、打开XP下DOS窗口具体操作是点击“开始”菜 ... [详细]
  • 深入解析Java虚拟机(JVM)架构与原理
    本文旨在为读者提供对Java虚拟机(JVM)的全面理解,涵盖其主要组成部分、工作原理及其在不同平台上的实现。通过详细探讨JVM的结构和内部机制,帮助开发者更好地掌握Java编程的核心技术。 ... [详细]
  • 深入解析Spring启动过程
    本文详细介绍了Spring框架的启动流程,帮助开发者理解其内部机制。通过具体示例和代码片段,解释了Bean定义、工厂类、读取器以及条件评估等关键概念,使读者能够更全面地掌握Spring的初始化过程。 ... [详细]
  • 深入解析动态代理模式:23种设计模式之三
    在设计模式中,动态代理模式是应用最为广泛的一种代理模式。它允许我们在运行时动态创建代理对象,并在调用方法时进行增强处理。本文将详细介绍动态代理的实现机制及其应用场景。 ... [详细]
  • 本题要求在一组数中反复取出两个数相加,并将结果放回数组中,最终求出最小的总加法代价。这是一个经典的哈夫曼编码问题,利用贪心算法可以有效地解决。 ... [详细]
author-avatar
透明
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有