hashmap 允许key重复吗_搞懂 HashMap,这一篇就够了

2023-11-09


HashMap 概述

「如果你没有时间细抠本文,可以直接看 HashMap 概述,能让你对 HashMap 有个大致的了解」

HashMap 是 Map 接口的实现,HashMap 允许空的 key-value 键值对,HashMap 被认为是 Hashtable 的增强版,HashMap 是一个非线程安全的容器,如果想构造线程安全的 Map 考虑使用 ConcurrentHashMap。HashMap 是无序的,因为 HashMap 无法保证内部存储的键值对的有序性。

HashMap 的底层数据结构是数组 + 链表的集合体,数组在 HashMap 中又被称为桶(bucket)。遍历 HashMap 需要的时间损耗为 HashMap 实例桶的数量 + (key - value 映射) 的数量。因此,如果遍历元素很重要的话,不要把初始容量设置的太高或者负载因子设置的太低。

HashMap 实例有两个很重要的因素,初始容量和负载因子,初始容量指的就是 hash 表桶的数量,负载因子是一种衡量哈希表填充程度的标准,当哈希表中存在足够数量的 entry,以至于超过了负载因子和当前容量,这个哈希表会进行 rehash 操作,内部的数据结构重新 rebuilt。

注意 HashMap 不是线程安全的,如果多个线程同时影响了 HashMap ,并且至少一个线程修改了 HashMap 的结构,那么必须对 HashMap 进行同步操作。可以使用 Collections.synchronizedMap(new HashMap) 来创建一个线程安全的 Map。

HashMap 会导致除了迭代器本身的 remove 外,外部 remove 方法都可能会导致 fail-fast 机制,因此尽量要用迭代器自己的 remove 方法。如果在迭代器创建的过程中修改了 map 的结构,就会抛出 ConcurrentModificationException 异常。

下面就来聊一聊 HashMap 的细节问题。我们还是从面试题入手来分析 HashMap 。

HashMap 和 HashTable 的区别

我们上面介绍了一下 HashMap ,现在来介绍一下 HashTable

相同点

HashMap 和 HashTable 都是基于哈希表实现的,其内部每个元素都是 key-value 键值对,HashMap 和 HashTable 都实现了 Map、Cloneable、Serializable 接口。

不同点

  • 父类不同:HashMap 继承了 AbstractMap 类,而 HashTable 继承了 Dictionary

47dac32408f508f15231d69417b85ac2.png

  • 空值不同:HashMap 允许空的 key 和 value 值,HashTable 不允许空的 key 和 value 值。HashMap 会把 Null key 当做普通的 key 对待。不允许 null key 重复。

3dcb58981fcd9d8b2f52a84d6dbcab23.png

  • 线程安全性:HashMap 不是线程安全的,如果多个外部操作同时修改 HashMap 的数据结构比如 add 或者是 delete,必须进行同步操作,仅仅对 key 或者 value 的修改不是改变数据结构的操作。可以选择构造线程安全的 Map 比如 Collections.synchronizedMap 或者是 ConcurrentHashMap。而 HashTable 本身就是线程安全的容器。
  • 性能方面:虽然 HashMap 和 HashTable 都是基于单链表的,但是 HashMap 进行 put 或者 get? 操作,可以达到常数时间的性能;而 HashTable 的 put 和 get 操作都是加了 synchronized 锁的,所以效率很差。

51accc5966668055a881eb04a2c7d4d8.png

  • 初始容量不同:HashTable 的初始长度是11,之后每次扩充容量变为之前的 2n+1(n为上一次的长度)

    而 HashMap 的初始长度为16,之后每次扩充变为原来的两倍。创建时,如果给定了容量初始值,那么HashTable 会直接使用你给定的大小,而 HashMap 会将其扩充为2的幂次方大小。

HashMap 和 HashSet 的区别

也经常会问到 HashMap 和 HashSet 的区别

HashSet 继承于 AbstractSet 接口,实现了 Set、Cloneable,、java.io.Serializable 接口。HashSet 不允许集合中出现重复的值。HashSet 底层其实就是 HashMap,所有对 HashSet 的操作其实就是对 HashMap 的操作。所以 HashSet 也不保证集合的顺序。

HashMap 底层结构

要了解一个类,先要了解这个类的结构,先来看一下 HashMap 的结构:

ab7a76b193ecb173e35a0e77d86941a7.png

最主要的三个类(接口)就是 HashMap,AbstractMapMap 了,HashMap 我们上面已经在概述中简单介绍了一下,下面来介绍一下 AbstractMap。

AbstractMap 类

这个抽象类是 Map 接口的骨干实现,以求最大化的减少实现类的工作量。为了实现不可修改的 map,程序员仅需要继承这个类并且提供 entrySet 方法的实现即可。它将会返回一组 map 映射的某一段。通常,返回的集合将在AbstractSet 之上实现。这个set不应该支持 add 或者 remove 方法,并且它的迭代器也不支持 remove 方法。

为了实现可修改的 map,程序员必须额外重写这个类的 put 方法(否则就会抛出UnsupportedOperationException),并且 entrySet.iterator() 返回的 iterator 必须实现 remove() 方法。

Map 接口

Map 接口定义了 key-value 键值对的标准。一个对象支持 key-value 存储。Map不能包含重复的 key,每个键最多映射一个值。这个接口代替了Dictionary 类,Dictionary是一个抽象类而不是接口。

Map 接口提供了三个集合的构造器,它允许将 map 的内容视为一组键,值集合或一组键值映射。map的顺序定义为map映射集合上的迭代器返回其元素的顺序。一些map实现,像是TreeMap类,保证了map的有序性;其他的实现,像是HashMap,则没有保证。

重要内部类和接口

Node 接口

Node节点是用来存储HashMap的一个个实例,它实现了 Map.Entry接口,我们先来看一下 Map中的内部接口 Entry 接口的定义

Map.Entry

// 一个map 的entry 链,这个Map.entrySet()方法返回一个集合的视图,包含类中的元素,// 这个唯一的方式是从集合的视图进行迭代,获取一个map的entry链。这些Map.Entry链只在// 迭代期间有效。interface Entry<K,V> {
    K getKey();V getValue();V setValue(V value);boolean equals(Object o);int hashCode();
}

Node 节点会存储四个属性,hash值,key,value,指向下一个Node节点的引用

 // hash值final int hash;// 键final K key;// 值
V value;// 指向下一个Node节点的Node类型
Node next;

因为Map.Entry 是一条条entry 链连接在一起的,所以Node节点也是一条条entry链。构造一个新的HashMap实例的时候,会把这四个属性值分为传入

Node(int hash, K key, V value, Node next) {
    this.hash = hash;this.key = key;this.value = value;this.next = next;
}

实现了 Map.Entry 接口所以必须实现其中的方法,所以 Node 节点中也包括上面的五个方法

KeySet 内部类

keySet 类继承于 AbstractSet 抽象类,它是由 HashMap 中的 keyset() 方法来创建 KeySet 实例的,旨在对HashMap 中的key键进行操作,看一个代码示例

77a2a26e161f003bdc17f6fb1919a137.png

图中把「1, 2, 3」这三个key 放在了HashMap中,然后使用 lambda 表达式循环遍历 key 值,可以看到,map.keySet() 其实是返回了一个 Set 接口,KeySet() 是在 Map 接口中进行定义的,不过是被HashMap 进行了实现操作,来看一下源码就明白了

// 返回一个set视图,这个视图中包含了map中的key。public Set keySet() {
    // // keySet 指向的是 AbstractMap 中的 keyset
  Set ks = keySet;if (ks == null) { // 如果 ks 为空,就创建一个 KeySet 对象// 并对 ks 赋值。
    ks = new KeySet();
    keySet = ks;
  }return ks;
}

所以 KeySet 类中都是对 Map中的 Key 进行操作的:

132746e4554771e41122f840b0316783.png

Values 内部类

Values 类的创建其实是和 KeySet 类很相似,不过 KeySet 旨在对 Map中的键进行操作,Values 旨在对key-value 键值对中的 value 值进行使用,看一下代码示例:

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

hashmap 允许key重复吗_搞懂 HashMap,这一篇就够了 的相关文章

  • CTF工具压缩包爆破神器Fcrackzip详细用法

    Fcrackzip简介 Fcrackzip是一款专门破解zip类型压缩文件密码的工具 工具小巧方便 破解速度快 能使用字典和指定字符集破解 适用于linux mac osx 系统 Fcrackzip下载 Windows下载 下载链接 htt
  • 「爬虫教程」吐血整理,最详细的爬虫入门教程

    初识爬虫 学习爬虫之前 我们首先得了解什么是爬虫 来自于百度百科的解释 网络爬虫 又称为网页蜘蛛 网络机器人 在FOAF社区中间 更经常的称为网页追逐者 是一种按照一定的规则 自动地抓取万维网信息的程序或者脚本 通俗来讲 假如你需要互联网上
  • Spring中Bean的实例化详细流程

    还是举个例子 我有一个朋友小汪他远赴南方某城市打工 然后安定下来后他的朋友很想来家里玩 但是呢我这个朋友家里搞的很乱 所以他不好意思请朋友来家里玩 这时我的另一个朋友说那请一个保姆把家里好好整理一下就可以了 然后给他介绍了一个保姆大S PS
  • C语言 信号处理机制

    C语言中信号标示一种时间 它可能异步地发生 也就是并不与城市执行过程中的任何事件保持同步 如果程序中未设置该信号的处理函数 则选择缺省方式 大部分为终止程序运行 信号头文件
  • 面向对象的编程思想和Python的类,访问和属性,继承

    面向对象的编程思想和Python的类 类的方法和属性 实例方法 这一文从面相对象的角度 介绍类的定义 类的属性和自定义方法 本文将从访问限制 属性 继承 方法重写这几个方面继续介绍面向对象的编程思想和Python类的继承 一 访问权限 Py
  • XML建模

    文章目录 思路 思路 把配置文件读到内存里并解析出来 gt 建立xml模型 有几个节点就创建几个模型 把他们的关系放到模型里 gt 对模型进行完善 gt 把解析出来的数据放到模型里 XML建模的具体文件 内附注释
  • Linux unit 测试工具,单元测试工具 CUnit 简介

    1 CUnit简介 1 1 CUnit简要描述 CUnit是一个编写 管理及运行c语言单元测试的系统 它使用一个简单的框架来构建测试结构 并为普通数据结构的测试提供丰富的断言 此外 CUnit为测试的运行和结果查看提供了许多不同的接口 包括
  • centos7 keepalived 离线安装

    两台服务器 master 10 214 130 100 slave 10 214 130 101 vip keepalived虚拟ip 10 214 130 102 1 下载 登陆官网 http www keepalived org dow
  • IDEA Maven 依赖分析插件Maven Helper

    IDEA 安装Maven Helper插件 1 打开setting 找到Plugins选项 安装Maven Helper 插件 如果有就跳过这一步 检索 Maven Helper 安装成功后 重新启动IDEA编辑器 2 使用Maven He
  • java 将pdf转word

    可以使用 Apache POI 库来实现将 PDF 转换为 Word 文档的功能 首先 需要将 Apache POI 库的依赖添加到项目中
  • 推荐几个很实用的编程网站

    目录 一 W3School 二 LeetCode 三 PythonTip 四 Codewars 五 Code Monkey 本文精选了有关代码 编程 Java Python SQL Git 和Ruby on Rails学习的网站 这些网站为
  • mac扩展屏,HIDPI

    2k 4k 均可开启 HIDPI
  • java.lang.RuntimeException: Canvas: trying to draw too large(277114284bytes) bitmap.

    java lang RuntimeException Canvas trying to draw too large 277114284bytes bitmap 今天运行一个小项目报错 E AndroidRuntime FATAL EXCE
  • 【PCL】得到一个点云中的最高值、最低值

    有一个点云 想得到它x y z三个轴上的最大值和最小值 可以用pcl getMinMax3D函数 在这儿 函数参数 1 点云 2 放最小值的容器 3 放最大值的容器 容器类型是点云中点的类型 正好有三个值 代码 Created by eth
  • 分布式事务-LCN

    2PC两阶段提交协议 分布式事务通常采用2PC协议 全称Two Phase Commitment Protocol 该协议主要为了解决在分布式数据库场景下 所有节点间数据一致性的问题 分布式事务通过2PC协议将提交分成两个阶段 阶段一为准备
  • 4. Redis高并发分布式锁实战---大厂生产级Redis高并发分布式锁实战

    分布式缓存技术Redis 1 手写分布式锁 2 Redis Lua 3 Redisson 4 redis分布式锁在集群中存在的问题 本文是按照自己的理解进行笔记总结 如有不正确的地方 还望大佬多多指点纠正 勿喷 课程内容 1 高并发场景秒杀
  • Elasticsearch 在kibana中对索引名称进行重命名

    问题 在实际的工作中 遇到已经将数据写入es 但是后边需要对这个索引进行重命名 如 test 20190122 test 20190121 需要重命名为test 2019 对于数据量比较少时 创建多个索引 需要创建多个分片 造成存储资源的浪
  • 正则表达式——Pattern.DOTALL

    项目测试过程中 测试发现短信内容无法正常解析成2个部分 代码如下 public static void main String args String testStr 13800000000 孔雀东南飞 五里一徘徊 n 十三能织素 十四学裁
  • 行式数据库与列式数据库的对比

    导语 随着大数据的发展 现在出现的列式存储和列式数据库 它与传统的行式数据库有很大区别的 正文 行式数据库是按照行存储的 行式数据库擅长随机读操作不适合用于大数据 像SQL server Oracle mysql等传统的是属于行式数据库范畴

随机推荐

  • C语言在控制台上实现鼠标操作的方法

    文章目录 了解windows库函数 了解句柄 实现思路与代码 在制作面向用户系统时 我们往往需要设置除输入参数外更为灵活的操作方式 例如鼠标点击 按键按下 无阻塞输入 等 同时 我们需要制作更为精美的 UI而不是简陋的黑白界面 然而 纯C语
  • 解决docker下nginx的多个站点互通问题

    系统为MAC 环境为docker mysql php nginx 问题描述 1 调试本地接口 方式为curl 请求 返回拒绝 业务上通过curl访问报错 Couldn t connect to server Failed to connec
  • git bash配置ssh 登录 Linux

    1 首先在 Linux 服务器上生成公钥和私钥文件 默认的存放目录在 ssh下 ssh keygen 可以将密码留空 这样之后就可以免密码登录 2 将私钥文件拷贝到本机 scp root 192 168 1 168 root ssh id
  • Ubuntu安装Protobuf,指定版本

    参考 https github com protocolbuffers protobuf readme https github com protocolbuffers protobuf blob v3 20 3 src README md
  • VirtualBox+WinDbg+Win7调试环境配置

    VirtualBox WinDbg Win7调试环境配置 火苗999 的博客 1 配置虚拟机串口如图 勾选启用串口 gt 端口选择COM1 gt 端口模式选择主机管道 gt 勾选创建管道 gt 端口文件位置输入 pipe com1 2 配置
  • 极简光线追踪入门

    阅读本文不需要任何图形学基础 这里抛砖引玉 希望勾起读者对光线追踪的兴趣 前言 光线追踪原理简单 并且可以抛开图形学的一堆理论 单独提出来讲 本文不需要任何图形学基础 看完本文后 将能够实现以下效果 图1 光线追踪效果 原理 光线追踪算法由
  • linux文件夹大小4096,Linux文件系统之文件、分区大小限制

    各种文件系统的限制 NTFS Windows 支持最大分区2TB 最大文件2TB FAT16 Windows 支持最大分区2GB 最大文件2GB FAT32 Windows 支持最大分区128GB 如果使用磁盘管理进行分区 最大为32GB
  • Docker自定义network搭建kafka

    昨天在搞spring cloud bus 想到用kafka实现消息总线 然后就用docker起了一个zookeeper和kafka 本人docker版本是17 06 采用机器是Ubuntu18版本 详细安装kafka的过程如下 1 dock
  • 反病毒工具-VirtualKD

    KD Kernel Debug 简介 它是一款 虚拟机辅助调试开源工具 版本支持情况 当前2 7版本支持Win8及以前系统 官网 http virtualkd sysprogs org 当你需要高效地调试一台虚拟机你需要它 双机调试的时候
  • VC中GDI绘图技术基础知识:hdc设备环境句柄,坐标系

    VC中GDI绘图技术 通过HDC设备环境句柄绘图有三种方式 标准客户区绘图 临时客户区绘图 非客户区绘图 1 标准客户区绘图 是在WM PAINT消息回调时执行 调用BeginPaint函数 EndPaint函数 2 临时客户区绘图 是在任
  • JSP+MVC开发模式 +EL表达式+ JSTL标签

    今日内容 1 JSP 1 指令 2 注释 3 内置对象 2 MVC开发模式 3 EL表达式 4 JSTL标签 5 三层架构 JSP 1 指令 作用 用于配置JSP页面 导入资源文件 格式 分类
  • ESP32 之 ESP-IDF 教学(十四)——虚拟文件系统(VFS)

    本文章 来自原创专栏 ESP32教学专栏 基于ESP IDF 讲解如何使用 ESP IDF 构建 ESP32 程序 发布文章并会持续为已发布文章添加新内容 每篇文章都经过了精打细磨 通过下方对话框进入专栏目录页 CSDN 请求进入目录 O
  • 安卓上基于透明代理抓包

    前言 在安卓上基于透明代理对特定APP抓包中使用的是redsocks2 本文演示如何使用clash实现同样的效果 你以为是Clash For Android 错 这里使用的是Core版本 就原理上来说 和前一篇文章并无区别 Clash的优势
  • Linux网络协议栈(五) -- 数据包的发送(based in 2.6.32)

    一 关键数据结构 对于输出封包 设备的数据结构主要包括两个 输出队列 queue 和输出队列规则 queue discipline 我们首先来看输出队列 2 6 18内核中无该结构体 struct netdev queue structne
  • 谈谈App混合开发

    混合开发的App Hybrid App 就是在一个App中内嵌一个轻量级的浏览器 一部分原生的功能改为Html 5来开发 这部分功能不仅能够在不升级App的情况下动态更新 而且可以在Android或iOS的App上同时运行 让用户的体验更好
  • 技术人修炼之道阅读笔记(六)解决对抗性思维方法

    技术人修炼之道阅读笔记 六 解决对抗性思维方法 网上经常看见产品经理和开发人员的段子 例如 杀死一个开发人员不用枪 只需要改三次需求 技术人开会 产品经理能安然无恙坐在这里 是因为门外有保安 等 这些都说明了产品经理和开发人员的矛盾 那么问
  • qt检查文件夹是否有写权限

    Qt 使用如下函数能够判断路径或者文件是否可写 bool QFileInfo isWritable const 对于win10系统实测 结果不准确 继续排查 官方文档描述 a 如果未启用 NTFS 权限检查 Windows 上的结果将仅反映
  • IDEA 程序包不存在,找不到符号但是明明存在对应的jar包 的解决方案

    注 本人刚开始是使用 Settings gt Build gt Build Tools gt Maven gt Runner gt 勾选上Delegagte IDE build run actions to Maven 这种办法 成功解决了
  • 内核管理-之进程虚拟内存-基于linux3.10

    关于启动过程内存管理见 内存管理 之启动 关于内核空间内存管理见 内存管理 之内核内存管理 如果需要 内存管理五章整理成pdf了 下载地址http download csdn net detail shichaog 8662135 进程的虚
  • hashmap 允许key重复吗_搞懂 HashMap,这一篇就够了

    HashMap 概述 如果你没有时间细抠本文 可以直接看 HashMap 概述 能让你对 HashMap 有个大致的了解 HashMap 是 Map 接口的实现 HashMap 允许空的 key value 键值对 HashMap 被认为是