JDK17 HashMap

news2025/1/27 7:39:42

HashMap

ArrayList用动态数组存放元素,而HashMap用动态数组(桶)存储键值对。
如果两个键值对映射到桶同一个索引,则称为散列冲突。HashMap采用拉链法解决冲突,即桶中每个索引指向一个链表或者红黑树,多个键值对存放在同一个链表/红黑树中。
拉链法的优点是:

  1. 链表是动态申请的,适合动态扩容的桶。
  2. 解决冲突方法比较简单,无堆积现象(非键冲突键值对不会冲突)。查找效率高。
  3. 键值对规模较大时可以充分利用桶索引,节省空间。

拉链法的缺点是:键值对规模较小时,浪费空间。而ThreadLocalMap用的就是开放地址法解决冲突。

构造器方法

HashMap的构造器方法有很多,最常见的有2个,一个设置初始容量,一个不设置初始容量。

方法含义
HashMap(int initialCapacity)指定初始容量
public HashMap()默认初始容量为16

推荐指定初始容量,原因是如果默认初始容量不足以存储元素,HashMap会扩容。每次扩容都会将元素重新计算哈希值并放入新桶,非常消耗性能。
因此初始容量设为expectedSize / 0.75F + 1.0F

public HashMap(int initialCapacity) {
    this(initialCapacity, DEFAULT_LOAD_FACTOR);
}
public HashMap(int initialCapacity, float loadFactor) {
    if (initialCapacity < 0)
        throw new IllegalArgumentException("Illegal initial capacity: " +
                                           initialCapacity);
    if (initialCapacity > MAXIMUM_CAPACITY) // MAXIMUM_CAPACITY = 1 << 30.也就是2的30次方。
        initialCapacity = MAXIMUM_CAPACITY; 
    if (loadFactor <= 0 || Float.isNaN(loadFactor))
        throw new IllegalArgumentException("Illegal load factor: " +
                                           loadFactor);
    this.loadFactor = loadFactor;
    // tableSizeFor方法是取比initialCapacity大的最小的2的次幂
    // threshold=capacity * load factor,数组容量超过threshold则扩容
    this.threshold = tableSizeFor(initialCapacity);
}

键值对

HashMap采用Node静态内部类存储元素。散列值是为了快速定位桶索引。next表示链表下一个Node节点。
在这里插入图片描述
如果链表达到一定规模,将链表转为红黑树存储元素。在这里插入图片描述

哈希映射

HashMap<K, V>的键可以是任意类型,为了将键对象映射为桶索引,第一步调用hash(Object key)方法将键对象散列为int类型散列值h

static final int hash(Object key) {
	int h;
	// 如果key == null, 则数组下标为0
	// 如果key != null, 调用key的hashCode()方法计算哈希值h
	//	   h >>> 16 是获取h的高16位
	//     h ^ (h >>> 16)是将低16位与高16位进行异或运算
    return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}

第二步,数组下标i = (n - 1) & hash,其中n是桶容量,且为2的次幂。第三步,HashMap将键值对存储在桶的索引i位置。

散列值h是int类型,范围很大。但是通常情况下,内存中数组容量不会太大,通常用不着h的高位。这会导致更频繁的冲突,即众多元素散列到同一个索引,导致部分索元素众多,部分索引元素过少,不平衡。为了解决这个问题,HashMap将低16位与高16位进行异或运算,意图减少冲突。

为了提高计算效率,HashMap规定桶的容量是2的次幂,使得(n - 1) & hash = hash % n与运算取模运算效率更高。当n是2的m次方,则n-1的低位是m个1,(n - 1)&hash就是将hash的低m位设为索引。

桶扩容

如果键值对越来越多,而桶不扩容,则单个索引的链表/红黑树会存放过多元素,影响查询效率。为了降低冲突,提高查询效率,因此桶扩容。

扩容时机是元素数量达到容量*加载因子,源码为size > threshold。默认加载因子是0.75,即数组中超过75%的索引不为空,为红黑树/链表,则扩容。

桶扩容源码在resize()方法。resize()方法第一部分是根据旧容量oldCap和旧阈值oldThr计算新容量newCap和新阈值newThr。主要有以下几种情况:

  1. 调用无参构造器后初次调用resize()方法,oldCap=0, oldThr = 0.则newCap = 16, newThr = 12
  2. 调用有参构造器HashMap(int initialCapacity)后初次调用resize()方法,oldCap = 0,oldThr不为0且为2的次幂,则newCap=oldThr, newThr=newCap*loadFactor
  3. 桶容量oldCap>=2^30,则threadhold设为最大值,表示不再扩容。
  4. oldCap >= 16, oldCap * 2 < 2^30,则newThr = oldThr * 2。即将阈值加倍。
    在这里插入图片描述
    得到阈值之后执行扩容。桶索引元素非空有3种情况:1. 红黑树。2. 链表。 3. 单个键值对。如果是单个键值对,则重新映射到新索引。
    在这里插入图片描述
    如果是链表,将其拆分为低位链表和高位链表,分别放在新桶的原索引和原索引+oldCap
    假设oldCap=16, newCap=32,则扩容前hash=3,hash=19, hash=35的元素都存在j=3的链表上。扩容后hash=3,hash=35仍然在j=3,而hash=19会移动到j=19HashMap试图将原链表的键值对均分到新链表的jj + oldCap索引。
    HashMap采用拉链法存储键值对。
    在这里插入图片描述

时间复杂度

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2283843.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ansible自动化运维实战--通过role远程部署nginx并配置(8)

文章目录 1、准备工作2、创建角色结构3、编写任务4、准备配置文件&#xff08;金甲模板&#xff09;5、编写变量6、编写处理程序7、编写剧本8、执行剧本Playbook9、验证-游览器访问每台主机的nginx页面 在 Ansible 中&#xff0c;使用角色&#xff08;Role&#xff09;来远程部…

Python网络自动化运维---用户交互模块

文章目录 目录 文章目录 前言 实验环境准备 一.input函数 代码分段解析 二.getpass模块 前言 在前面的SSH模块章节中&#xff0c;我们都是将提供SSH服务的设备的账户/密码直接写入到python代码中&#xff0c;这样很容易导致账户/密码泄露&#xff0c;而使用Python中的用户交…

计算机的错误计算(二百二十二)

摘要 利用大模型化简计算 实验表明&#xff0c;虽然结果正确&#xff0c;但是&#xff0c;大模型既绕了弯路&#xff0c;又有数值计算错误。 与前面相同&#xff0c;再利用同一个算式看看另外一个大模型的化简与计算能力。 例1. 化简计算摘要中算式。 下面是与一个大模型的…

mybatis(78/134)

前天学了很多&#xff0c;关于java的反射机制&#xff0c;其实跳过了new对象&#xff0c;然后底层生成了字节码&#xff0c;创建了对应的编码。手搓了一遍源码&#xff0c;还是比较复杂的。 <?xml version"1.0" encoding"UTF-8" ?> <!DOCTYPE …

数据分箱 baggingboosting onehot独热编码 woe编码 sklearn的ensemble(集成学习)

目录 数据分箱就是将连续变量离散化。 bagging&boosting onehot独热编码 独热编码的结果如下&#xff1a; woe编码 WOE编码的基本原理 步骤一&#xff1a;计算WOE 步骤二&#xff1a;应用WOE WOE编码的优点 示例 数据示例 步骤一&#xff1a;计算每个类别的违约…

企业微信开发010_使用WxJava企业微信开发框架_封装第三方应用企业微信开发003_并且实现多企业授权访问---企业微信开发012

继续来看吧,上一节,已经把config部分,代码都拿过来了: 并且把企业微信第三方应用开发部分,对应的config的配置,mutiltp 代码拿过来了,并且把yml中的配置也给出了. 然后,这里说一下config中的内容,到时候自己看也可以看懂 其实就是封装了,当系统启动,加载企微模块,这个时候,会…

Office2021下载与安装保姆级教程【Office Tool Plus】

Office Tool Plus安装Office2021 下载Office Tool Plus安装OfficeⅠ. 清除旧版本Ⅱ. 配置安装参数Ⅲ. 安装许可证Ⅳ. 激发&#xff08;JH&#xff09;Office 本文介绍使用Office Tool Plus工具下载、安装、部署Office 2021全过程。 下载Office Tool Plus OfficeToolPlus是一个…

Unity在WebGL中拍照和录视频

原工程地址https://github.com/eangulee/UnityWebGLRecoder Unity版本2018.3.6f1&#xff0c;有点年久失修了 https://github.com/xue-fei/Unity.WebGLRecorder 修改jslib适配了Unity2021 效果图 录制的视频 Unity在WebGL中拍照和录视频

【外文原版书阅读】《机器学习前置知识》1.线性代数的重要性,初识向量以及向量加法

目录 ​编辑 ​编辑 1.Chapter 2 Why Linear Algebra? 2.Chapter 3 What Is a Vector? 个人主页&#xff1a;Icomi 大家好&#xff0c;我是Icomi&#xff0c;本专栏是我阅读外文原版书《Before Machine Learning》对于文章中我认为能够增进线性代数与机器学习之间的理解的…

SpringBoot开发(二)Spring Boot项目构建、Bootstrap基础知识

1. Spring Boot项目构建 1.1. 简介 基于官方网站https://start.spring.io进行项目的创建. 1.1.1. 简介 Spring Boot是基于Spring4框架开发的全新框架&#xff0c;设计目的是简化搭建及开发过程&#xff0c;并不是对Spring功能上的增强&#xff0c;而是提供了一种快速使用Spr…

【PyTorch】4.张量拼接操作

个人主页&#xff1a;Icomi 在深度学习蓬勃发展的当下&#xff0c;PyTorch 是不可或缺的工具。它作为强大的深度学习框架&#xff0c;为构建和训练神经网络提供了高效且灵活的平台。神经网络作为人工智能的核心技术&#xff0c;能够处理复杂的数据模式。通过 PyTorch&#xff0…

新电脑安装系统找不到硬盘原因和解决方法来了

有不少网友反馈新电脑采用官方u盘方式装win10或win100出现找不到硬盘是怎么回事&#xff1f;后来研究半天发现是bios中开启了rst(vmd)模式。如果关闭rst模式肯定是可以安装的&#xff0c;但这会影响硬盘性能&#xff0c;有没有办法解决开启rst模式的情况安装win10或win11呢&…

「 机器人 」仿生扑翼飞行器中的“被动旋转机制”概述

前言 在仿生扑翼飞行器的机翼设计中,模仿昆虫翼的被动旋转机制是一项关键技术。其核心思想在于:机翼旋转角度(攻角)并非完全通过主动伺服来控制,而是利用空气动力和惯性力的作用,自然地实现被动调节。以下对这种设计的背景、原理与优势进行详细说明。 1. 背景:昆虫的被动…

Android GLSurfaceView 覆盖其它控件问题 (RK平台)

平台 涉及主控: RK3566 Android: 11/13 问题 在使用GLSurfaceView播放视频的过程中, 增加了一个播放控制面板, 覆盖在视频上方. 默认隐藏setVisibility(View.INVISIBLE);点击屏幕再显示出来. 然而, 在RK3566上这个简单的功能却无法正常工作. 通过缩小视频窗口可以看到, 实际…

【C++】类和对象(五)

1、初始化列表 作用&#xff1a;C提供了初始化列表语法&#xff0c;用来初始化属性。 语法&#xff1a; 构造函数&#xff08;&#xff09;&#xff1a;属性1&#xff08;值1&#xff09;&#xff0c;属性2&#xff08;值2&#xff09;...{}示例&#xff1a; #include<i…

Maven的下载安装配置

maven的下载安装配置 maven是什么 Maven 是一个用于 Java 平台的 自动化构建工具&#xff0c;由 Apache 组织提供。它不仅可以用作包管理&#xff0c;还支持项目的开发、打包、测试及部署等一系列行为 Maven的核心功能 项目构建生命周期管理&#xff1a;Maven定义了项目构建…

Mysql主从复制+MHA实验笔记[特殊字符]

目录 基本概念 工作原理 优势 环境准备&#xff1a;四台centos-其中三台mysql&#xff0c;一台MHA 配置一主两从 安装MHA 配置无密码认证 配置MHA 模拟master故障 基本概念 MySQL 主从复制&#xff1a;是 MySQL 数据库中实现数据冗余、数据备份和高可用性的重要技术手…

面向长文本的多模型协作摘要架构:多LLM文本摘要方法

多LLM摘要框架在每轮对话中包含两个基本步骤:生成和评估。这些步骤在多LLM分散式摘要和集中式摘要中有所不同。在两种策略中,k个不同的LLM都会生成多样化的文本摘要。然而在评估阶段,多LLM集中式摘要方法使用单个LLM来评估摘要并选择最佳摘要,而分散式多LLM摘要则使用k个LLM进行…

Python中容器类型的数据(上)

若我们想将多个数据打包并且统一管理&#xff0c;应该怎么办? Python内置的数据类型如序列(列表、元组等)、集合和字典等可以容纳多项数据&#xff0c;我们称它们为容器类型的数据。 序列 序列 (sequence) 是一种可迭代的、元素有序的容器类型的数据。 序列包括列表 (list)…

[Qt]系统相关-网络编程-TCP、UDP、HTTP协议

目录 前言 一、UDP网络编程 1.Qt项目文件 2.UDP类 QUdpSocket QNetworkDatagram 3.UDP回显服务器案例 细节 服务器设计 客户端设计 二、TCP网络编程 1.TCP类 QTcpServer QTcpSocket 2.TCP回显服务器案例 细节 服务器设计 客户端设计 三、HTTP客户端 1.HTTP…