无锡网站建设公司/附近电脑培训学校
《从0到1常用Map集合核心摘要+不深不浅底层核心》
前置知识
什么是键值对
键值对是一种数据结构,键是唯一标识,值是对应数据,用来快速查找信息。例:
{"name": "Alice"}
,键是name
,值是Alice
。
这听起来有些抽象, 为什么不能值就是数据呢? 还要多一个键
实际上, 键可能只是一个用于 ‘描述/标识’ 值的信息, 它的值可能是一个对象, 或一 个数组, 甚至更多复杂的东西,
但是无论有多复杂, 都可以通过一个 键
找到
而你的键, 可能连 5 个字母都没有
补充:并且直接存储值时,每个值的含义会很模糊。键则提供信息,比如
name: "Alice"
更直观,而不是单独存 "Alice"
。
map 集合是干嘛用的?
map集合就是用来存储一组或多组键值对的, 为了方便我们使用键值对, 其中封装了很多 方法, 供我们操作键值对
所有Map集合的接口 “Map”
- 一个接口, 其中包含的所有实现类都是 同一套数据结构(键值对)
介绍
-
Map 集合是一种双列集合, 每个元素包含两个数据, 一个是键一个是值
-
特点
- 键唯一 每个键唯一, 值可重复
- 易查 通过键定位值, 提高访问效率及便利性
- 灵活 通过泛型可存储各类数据, 无论是键或值
-
每个元素的格式
-
key = value : 键值对
-
key (键) : 非重
-
value (值) : 可重
-
关联性 : 键绑值, 哪怕不同键同值, 地址也不一样
-
一键多值 : 结合使用双列集合和单列集合, 来完成一键多值
-
-
键值对
-
一个整体, 在 JAVA 中使用 Entry 对象来表示
-
使用场景 :
购物车 -> 选择商品 -> 结算 …*每个店铺对应一个商品, 有时候一个有时候多个, 每个商品使用一个商品封装成一个对象来进行维护, 多个商品应当使用多个商品对象的单列集合装起来, 这样一个结算订单就有了多个商品*
-
总结 : 遇到键对值 (一个对多个), 就使用双列集合
-
-
常用公共方法、实现关系
V put(K key,V value) : // 添加键值对, 返回被覆盖的值 (没有覆盖则null)
V remove(Object key) : // 根据键删除键值对, 返回被删除的键对应的值boolean containsKey(Object key) : //判断集合指定键, 返回是或否
boolean containsValue(Object value) : //判断集合指定值, 返回是或否void Clear() : // 清空所有的键值对
boolean isEmpty() : //判断集合是否为空
int size() : //集合的长度 (键值对个数)
常用双列集合
TreeMap (红黑树)
HashMap (哈希表)
LinkedHashMap (哈希表 + 双向链表)
使用介绍
HashMap 的底层逻辑
- put 方法 : 双列集合中的添加
- put 方法执行中, 键和值会封装为一个 Entry(键值对) 对象
- 但实际在计算应存入索引时, 是拿着键进行计算的, 和值没有关系
(先调用对象计算原始哈希值, 再使用原始哈希值做一次哈希扰动, 然后再使用扰动过的哈希值做一次异或操作进行二次哈希, 最后再取余底层数组长度(16))…
方法演示
添加 : put(K key, V value)
/* Map是接口, 接口不能直接用, 所以通过多态一个子类或实现类 */
Map<String, String> map = new HashMap<>(); // 对HashMap 进行操作
map.put("张三","北京"); //put: 添加一个键值对 一是键二是值
map.put("李四","北京"); // 键重复时警告, 右边重复则没事, 说明键的不可重, 值的可重
map.put("王五","北京");// 北京 -> 仅一个
// 张三, 李四, 王五 -> 对应多个
System.out.println(map);// 打印成乱序, 是因为底层是哈希表// **put方法的返回值 被替换掉的旧值
String str = map.put("lala", "北京");
String str2 = map.put("lala", "喵");
System.out.println(str);
// 返回被覆盖掉的旧值, 没有重复就直接存
System.out.println(str2);
// -- 该返回值一般不接收 --
put方法的细节 (修改)( 条件 : 如果出现重键, 保留新键替换旧键 )
删除 : remove(Object key)
/* Remove 根据键删除 */
Map<String,String> map = new HashMap<>();
map.put("张三","南宁");
map.put("李四","上海");
map.put("王五","南宁");
System.out.println(map);map.remove("张三");
System.out.println(map);//返回值
String accept = map.remove("王五");
System.out.println(accept); // 返回为被删除键对应的值 - > 南宁
- 清空, 非空, 大小, 内容
- clear()、IsEmpty()、Size()、2个Contain() 一个比键一个比值
Map<String,String> map = new HashMap<>();
map.put("牛","马");
map.put("羊","马");
map.put("猪","马");
map.put("屎","马");System.out.println(map);
/* 判断是否存在指定数据 */
System.out.println(map.containsKey("牛")); -> true
System.out.println(map.containsValue("王")); - > false
System.out.println("-------------------------------------------");/* 清空,判断内容是否存在,判断非空 */
map.clear();
System.out.println(map); -> []
System.out.println(map.isEmpty()); -> true
System.out.println(map.size()); -> 0
泛型为自定义类时
// HashMap : 虽然说是键唯一, 但是底层依赖于哈希算法和内容比较
// 所以自定义类依然要重写 '两个哈希方法'
HashMap<Person,String> hm = new HashMap<>();
hm.put(new Person("张三",24),"上海");
hm.put(new Person("李四",23),"广东南宁");
hm.put(new Person("李四",23),"上海哈尔滨");
hm.put(new Person("王五",21),"上海");
hm.put(new Person("牛六",22),"上海");
System.out.println(hm);
// 没有重写两个哈希方法就会导致没有去重System.out.println(hm);
//HashMap底层也是哈希表结构,自定义类不重写 'hashCode和equal' 就无法去重, 而我们经常用的Bean类就重写过 这两个方法
排序 : 使用TreeMap集合
//TreeMap : 键排序
TreeMap<Person,String> hm = new TreeMap<>();
hm.put(new Person("张三",24),"上海");
hm.put(new Person("李四",23),"广东南宁");
hm.put(new Person("李四",23),"上海哈尔滨");
hm.put(new Person("王五",21),"上海");
hm.put(new Person("牛六",22),"上海");
System.out.println(hm);
//类型转换异常, 不能转换为 Java.lang.Comparable,
//如果键是自定义类(如 Person),没有实现 Comparable 接口,就无法比较两个键,导致报错:
// ClassCastException: Person cannot be cast to java.lang.Comparable。//总结 : 键排序 (实现Comparable接口, 重写comparable方法)
注意事项 : ** TreeMap 之所以可以在 HashCode 存储无序特性下进行排序, 实际上是因为他实现了Comparable 自然排序接口, 使用了 CompareTo 方法, 所以当我们使用 TreeMap 并指定泛型为自定义类时, 就需要重写 compareTo 方法**, 并且自定义类下要重写 hashCode() 和 equals(), 确保键的唯一性
LinkedHashMap 和 HashMap ↑一样的操作
// LinkedHashMap : 键唯一, 且可以保证存取顺序
LinkedHashMap<Person,String> hm = new LinkedHashMap<>();
hm.put(new Person("张三",23),"上海");
hm.put(new Person("李四",25),"南宁");
hm.put(new Person("王五",29),"此时");
System.out.println(hm);
下面统一讲
Map 集合中的三种遍历方式
-
摘要
-
通过键找值
V get(Object key) 根据键查找对应的值
Set keySet() 获取 Map 集合中所有的值– 配合使用 : 通过 Set 拿到每一个键, 再通过get 拿到每一个值 –
-
通过键值对对象获取键和值
-
通过forEach遍历
-
-
遍历方式演示
- 第一种遍历 (keySet,get)
| 第一种方式: 结合两种方法 | //V get(Object key) : 根据键找对应的值 //Set<K> keSet() : 获取 Map 集合中所有的键HashMap<String,String> hs = new HashMap<>(); hs.put("张三","北京"); hs.put("李四","上海"); hs.put("王五","牛牛");// 获取到所有的键 Set<String> set = hs.keySet(); System.out.println(hs);//遍历的set集合 for(String key:set){ // 获取泛型为String类型的键//调用get方法String content = hs.get(key);//根据键拿对应的值System.out.println("键: "+key+" 值: "+content); }
- 第二种遍历 (封装为Entry)
// 第二种 // 通过键值对对象获取键和值 Map.Entry(内部类) // 遍历要使用到的方法名 : // getKey() : 获取键 // getValue() : 获取值 // Set<Map.Entry<K,V>> entrySet() : 获取集合中所有的键值对对象 (接收getKey和getValue) // 配合使用, 获取键, 获取值, 根据键和值获取对象HashMap<String,String> hs = new HashMap<>(); hs.put("张三","北京"); hs.put("李四","上海"); hs.put("王五","牛牛");// 1. 获取所有的键值对对象 Set<Map.Entry<String,String>> entrySet = hs.entrySet(); // 格式剖析 : Set接口指定泛型, Map 中的内部类 Entry 也要指定泛型,键和值都是String 没了// 2. 遍历set集合获取每一个键值对对象 for(Map.Entry<String,String> keyV : entrySet){// 3. 通过键值对对象, 获取键和值System.out.println(keyV.getKey() + " | " + keyV.getValue()); }/*总结 :1.调用 entrySet方法获取所有的键值对对象 (得到的是Set集合)2.遍历 Set 集合, 获取每一个键值对对象3. 通过键值对对象的 getKey() getValue() 获取键和值*/
- 第三种遍历方式 (forEach)
// Map 集合中的三种遍历方式 // 通过foreach 方法便利 /* default void forEach(BiConsumer<? super K,? super V> action)-- 遍历 Map 集合 ,获取键和值 */ HashMap<String,String> hs = new HashMap<>(); hs.put("张三","北京"); hs.put("李四","上海"); hs.put("王五","牛牛");/* 一个函数式接口 */ hs.forEach(new BiConsumer<String, String>() {@Overridepublic void accept(String s1, String s2) {System.out.println(s1 + " | " + s2);} });
Map 集合练习
/*Map 集合练习 (单列集合结合双列集合)定义一个Map集合, 键用表示身份名称, 值表示市添加完毕后, 遍历结果:格式如下:江苏省 = 南京市, 扬州市, 苏州市, 无锡市, 常州市湖北省 = 武汉市, 孝感市, 十堰市, 宜昌市, 鄂州市四川省 = 成都市, 绵阳市, 自贡市, 攀枝花市, 泸州市*/
| 思路 : 单列集合做值, 双列集合做键 |ArrayList<String> list = new ArrayList<>();
HashMap<String,ArrayList<String>> map = new HashMap<>();
Collections.addAll(list,"南京市","扬州市","苏州市","无锡市","常州市");| 结合 |
map.put("江苏省",list);ArrayList<String> list2 = new ArrayList<>();
Collections.addAll(list2,"武汉市","孝感市","十堰市","宜昌市","鄂州市");
map.put("湖北省",list2);ArrayList<String> list3 = new ArrayList<>();
Collections.addAll(list3,"成都市","绵阳市","自贡市","攀枝花市","泸州市");
map.put("四川省",list3);map.forEach((k, v) -> System.out.println(k+" = "+v));
// 第二种遍历方式回温
System.out.println("-----------------------------------");| 封装为键值对对象 |
Set<Map.Entry<String, ArrayList<String>>> entries = map.entrySet();| 遍历 |
for (Map.Entry<String, ArrayList<String>> entry : entries) {System.out.println(entry.getKey() + " = " + entry.getValue());
}
有意思的底层
以下是对 Map 接口详解的进一步拓展,包含数据结构、底层实现和内存优化等方面的深入分析。
Map 的底层数据结构
HashMap 的底层结构
-
数组 + 链表 + 红黑树:
- HashMap 的底层是一个数组(哈希桶),每个桶存储一个链表或红黑树。
- 当发生哈希冲突(即多个键映射到相同的桶时),HashMap 会将这些键值对组织成一个链表存储。
- 如果链表长度超过一定阈值(默认 8),链表会被转换为红黑树,提升查找效率。
- 如果桶内元素数量小于阈值(默认 6),红黑树会退化为链表。
-
哈希计算逻辑:
- 键的哈希值由
hashCode
方法计算,通过扰动函数进一步优化,使其分布更均匀。 - 通过
(n - 1) & hash
确定哈希桶的索引(n
是数组长度)。 - 这种位运算比取模操作更高效。
- 键的哈希值由
-
动态扩容:
- 当 HashMap 的元素数量超过数组容量的 75%(默认负载因子 0.75),数组会扩容为原大小的两倍,并重新计算所有键的哈希位置。
TreeMap 的底层结构
-
红黑树:
- TreeMap 基于红黑树实现,是一种自平衡二叉搜索树。
- 插入键时,TreeMap 会根据键的自然顺序(或自定义比较规则)排列节点。
- 查找、插入和删除的时间复杂度为 O(log n)。
-
排序功能:
- 键需实现
Comparable
接口,或在 TreeMap 构造时传入一个自定义Comparator
。
- 键需实现
3. LinkedHashMap 的底层结构
-
哈希表 + 双向链表:
-
LinkedHashMap 是 HashMap 的子类,保留了键值对插入的顺序。
-
通过双向链表维护插入顺序或访问顺序(可配置)。
-
适用于需要有序遍历的场景,如缓存实现。
-
Map 的性能优化
1. 选择合适的实现类
- 如果不关心顺序,优先使用 HashMap,其增删改查操作最为高效(均摊复杂度为 O(1))。
- 如果需要按插入顺序或访问顺序遍历键值对,选择 LinkedHashMap。
- 如果需要键自动排序,选择 TreeMap。
总结与比较
Map 实现类 | 底层数据结构 | 特点 | 适用场景 |
---|---|---|---|
HashMap | 数组 + 链表/红黑树 | 高效、无序 | 快速查找,键值无序的场景。 |
TreeMap | 红黑树 | 自动排序 | 需要按键排序的场景。 |
LinkedHashMap | 哈希表 + 双向链表 | 插入/访问顺序一致 | 缓存、按插入顺序遍历。 |
相关文章:

《从0到1常用Map集合核心摘要 + 不深不浅底层核心》
《从0到1常用Map集合核心摘要不深不浅底层核心》 前置知识 什么是键值对 键值对是一种数据结构,键是唯一标识,值是对应数据,用来快速查找信息。例: {"name": "Alice"},键是name,…...

12 设计模式之工厂方法模式
一、什么是工厂方法模式? 1.定义 在软件开发中,设计模式 是解决常见软件设计问题的最佳实践。而 工厂方法模式(Factory Method Pattern) 作为创建型设计模式之一,常常被用来解决对象创建问题。它通过将对象的创建交给…...

spaCy 入门与实战:强大的自然语言处理库
spaCy 入门与实战:强大的自然语言处理库 spaCy 是一个现代化、工业级的自然语言处理(NLP)库,以高效、易用和功能丰富著称。它被广泛应用于文本处理、信息提取和机器学习任务中。本文将介绍 spaCy 的核心功能,并通过一…...

python包的管理和安装——笔记
1.列出包 pip list pip freeze 用这2个可以查看当前python 下所有的包和版本,还有下载地址 如果只是想导出当前的环境 可以用 2.安装pipreqs pip install pipreqs,pipreqs ./可以导出当前项目的包这个包 遇到编码报错 pipreqs ./ --encodingutf8 p…...

Vue前端页面内嵌套本项目iframe窗口的通信传输方式
一、目的 想要在iframe中使用本项目页面、并能够与其父页面组件实现实时通信。Vue前端页面内嵌套本项目iframe窗口的通信传输方式-星林社区 https://www.jl1mall.com/forum/PostDetail?postId20241202172800023969 二、iframe通信方式 1.接收消息 页面需要监听 message 事件…...

【WEB开发.js】addEventListener事件监听器的绑定和执行次数的问题(小心踩坑)
假设我们有一个按钮,用户点击该按钮后,会选择一个文件,且我们希望每次点击按钮时只触发一次文件处理。下面我会给你一个简单的例子,展示放在函数内部和放在函数外部的区别。 1. 将事件监听器放在函数内部(问题的根源&…...

用于LiDAR测量的1.58um单芯片MOPA(一)
--翻译自M. Faugeron、M. Krakowski1等人2014年的文章 1.简介 如今,人们对高功率半导体器件的兴趣日益浓厚,这些器件主要用于遥测、激光雷达系统或自由空间通信等应用。与固态激光器相比,半导体器件更紧凑且功耗更低,这在低功率供…...

【GPT】代谢概念解读
以下是对代谢中分解代谢和合成代谢两个概念的深入解读,用简单易懂的方式展开说明: 1. 分解代谢(Catabolism) 什么是分解代谢? 分解代谢是身体把大分子“拆开”的过程。就像把一个三明治分解成面包片、肉片和菜叶&#…...

Devops-git篇-01-git环境配置
环境配置 设置用户签名 配置用户名: git config --global user.name 你的用户名 配置邮箱: git config --global user.email 注册的邮箱 配置好之后,可以用git config --global --list命令查看配置是否OK $ git config --global --list u…...

STM32 HAL库开发学习1.STM32CubeMX 新建工程
STM32 HAL库开发学习1.STM32CubeMX 新建工程 一、 STM32 CubeMX 下载二、CubeMX 功能介绍1. 固件包路径设置2. 新建工程 三、创建项目实例1. 新建项目2. GPIO 管脚设置3. GPIO 窗口配置4. 调试设置5. 时钟配置6. 项目管理(1)项目信息(2&#…...

JS学习(2)(浏览器执行JS过程、JS的ECMAScript、DOM、BOM)
目录 一、浏览器如何执行JS? (1)浏览器主要的组成部分。 1、渲染引擎。 2、JS引擎。 (2)演示。 二、JS的组成。 (1)JS主要由三部分组成。 1、JS基础。 2、JS-API。 (2)EC…...

如何解决服务器扫描出的ASP木马问题
随着互联网的发展,网站安全问题日益凸显。其中,ASP(Active Server Pages)木马因其隐蔽性和危害性成为攻击者常用的手段之一。本文将详细介绍如何检测和清除服务器上的ASP木马,以保障网站的安全。 1. ASP木马概述 ASP…...

SpringBoot 架构助力夕阳红公寓管理系统可持续发展战略
摘 要 如今社会上各行各业,都在用属于自己专用的软件来进行工作,互联网发展到这个时候,人们已经发现离不开了互联网。互联网的发展,离不开一些新的技术,而新技术的产生往往是为了解决现有问题而产生的。针对于夕阳红公…...

TCP、HTTP、RPC
一、TCP (Transmission Control Protocol) 定义 TCP(传输控制协议)是一种面向连接、可靠传输的传输层协议,用于在计算机网络中提供端到端的数据通信服务。它是互联网协议套件的一部分,与IP(互联网协议)一…...

《C++ 中 RNN 及其变体梯度问题的深度剖析与解决之道》
在当今人工智能蓬勃发展的浪潮中,递归神经网络(RNN)及其变体长短期记忆网络(LSTM)和门控循环单元(GRU)在处理序列数据方面展现出了强大的潜力。然而,当我们在 C中着手实现这些网络时…...

TypeScript 在 React 中的应用
文章目录 前言一、为什么要在 React 中使用 TypeScript?二、如何在React中使用 TypeScript三、高级类型结语 前言 随着前端开发的复杂度不断提升,开发者对于代码质量、可维护性和开发效率的要求也日益增高。TypeScript 作为一种为 JavaScript 添加静态类…...

黑马2024AI+JavaWeb开发入门Day07-部门管理-日志技术飞书作业
视频地址:哔哩哔哩 讲义作业飞书地址:day07作业 完成新增班级和查询班级的接口开发 1、ClazzController.java package org.example.controller;import lombok.extern.slf4j.Slf4j; import org.example.pojo.Clazz; import org.example.service.Clazz…...

UIlicious - 自动化端到端测试
在现代软件开发中,测试自动化已然成为产品交付质量的基石。而端到端测试(E2E),作为验证整个应用流畅运行的关键,常常是测试工作中最具挑战性的一环。这时,一款简单高效的自动化测试工具——UIlicious&#…...

JMeter中获取随机数、唯一ID、时间日期(包括当前日期增减)截取指定位数的字符等
在JMeter中,您可以使用内置的函数和一些额外的插件来获取随机数、唯一ID、时间日期以及截取指定位数的字符。以下是一些常用的方法: 获取随机数: 使用__Random函数,您可以在指定的最小值和最大值之间生成一个随机数。例如…...

构建自己的docker的ftp镜像
aarch64系统可运行的docker镜像 构建自己的vsftpd镜像,我是在windows系统下的docker desktop中构建运行于aarch64 GNU/Linux系统的ftp镜像。 系统环境: Welcome to Debian GNU/Linux with Linux x.x.x dockerfile FROM ubuntu:latestUSER rootRUN ap…...

人机交互革命,为智能座舱市场激战注入一针「催化剂」
从AIGC到AGI赋能,智能座舱人机交互体验迎来新范式。 不断训练、迭代的大模型,为智能座舱带来了更全面的感知能力、更准确的认知理解,以及更丰富的交互模态,显著提升了其智能化水平。 “AI大模型的快速应用与迭代,推动…...

数据结构复习记录
基本概念 线性表 线性表是最简单也最常用的一种数据结构,是由n( n ≥ 0 n\geq0 n≥0)个类型相同的数据元素组成的有限序列,是一种逻辑结构,有两种表示方式(即存储结构):顺序表示和链式表示。 栈和队列 栈…...

Qt自定义checkbox实现按下回车键该项打勾
引言 开发环境代码结构示例代码运行效果总结使用qt实现一个列表,列表中每一项中的类似一个checkbox,通过上下键可以切换选中项,按下回车键在已经选中的项前出现对勾。效果如下: 20241203_163929 开发环境 使用ubuntu下QtCreator4.11.。 代码结构 这里将项目的结构截图贴…...

头歌作业 数据库与大数据管理 期末复习资料
1、 下列说法错误的是?c A、UserCF算法推荐的是那些和目标用户有共同兴趣爱好的其他用户所喜欢的物品 B、ItemCF算法推荐的是那些和目标用户之前喜欢的物品类似的其他物品 C、UserCF算法的推荐更偏向个性化 D、UserCF随着用户数目的增大,用户相似度…...

2023年华数杯数学建模A题隔热材料的结构优化控制研究解题全过程文档及程序
2023年华数杯全国大学生数学建模 A题 隔热材料的结构优化控制研究 原题再现: 新型隔热材料 A 具有优良的隔热特性,在航天、军工、石化、建筑、交通等高科技领域中有着广泛的应用。 目前,由单根隔热材料 A 纤维编织成的织物,…...

如何抓取亚马逊页面动态加载的内容:Python爬虫实践指南
引言 在现代电商领域,数据的重要性不言而喻。亚马逊作为全球领先的电商平台,其页面上动态加载的内容包含了丰富的商品信息。然而,传统的爬虫技术往往难以应对JavaScript动态加载的内容。本文将详细介绍如何使用Python结合Selenium工具来抓取…...

在线钢琴源码
在线钢琴源码 是利用HTML5技术开发的在线钢琴应用,致力于为钢琴爱好者、音乐爱好者提供一个优雅、简洁的平台 在学习工作之余可以在线弹钢琴,享受音乐、生活的美好。自由钢琴支持自动演奏和手动演奏,简单易学,快来试试吧 源码截…...

【OpenDRIVE_Python】使用python脚本输出OD数据中含有信号灯地物的道路ID和信号灯信息
示例代码说明: 遍历OD数据中每条道路Road,若Road中存在信号灯地物signal,则将该道路ID和包含的所有信号灯输出到xml文件中。补充:一个Road中可能存在多个信号灯signal,这里取signal的上级标签signals,则将所有信号灯同…...

普中51单片机——LED流水灯模块
1、GPIO概念 GPIO(general purpose intput output)是通用输入输出端口的简称,可以通过软件来控制其输入和输出。51 单片机芯片的 GPIO 引脚与外部设备连接起来,从而实现与外部通讯、 控制以及数据采集的功能。 1.1、GPIO分类 &a…...

智已汽车x-signature 登录算法 签到
智已汽车x-signature 登录算法 签到 python代码成品...