Java基础关键_021_集合(五)
目 录
一、HashMap
1.key 存储自定义类型
2.Hash 表存储原理
3.重写 hashCode 和 equals 方法
4.key 为 null
5.jdk 8 后新特性
(1)初始化时
(2)插入
(3)数据结构
6.容量
二、LinkedHashMap
1.说明
2.实例
三、Hashtable
1.说明
2.实例
3.特有方法
四、Properties
1.说明
2.实例
一、HashMap
1.key 存储自定义类型
public class Student {private String name;private int age;public Student(String name, int age) {this.name = name;this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", age=" + age +'}';}@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;Student student = (Student) o;return age == student.age && Objects.equals(name, student.name);}
}
public class HashMapTest {public static void main(String[] args) {HashMap<Student, Integer> hashMap = new HashMap<>();Student s1 = new Student("瑶", 18);Student s2 = new Student("刘禅", 19);Student s3 = new Student("朵莉亚", 20);Student s4 = new Student("蔡文姬", 21);Student s5 = new Student("钟馗", 22);Student s6 = new Student("钟馗", 22);System.out.println(s5.equals(s6)); // trueSystem.out.println(s5.hashCode()); // 990368553System.out.println(s6.hashCode()); // 1096979270System.out.println(s5.hashCode() % 16); // 9System.out.println(s6.hashCode() % 16); // 6hashMap.put(s1, 1);hashMap.put(s2, 2);hashMap.put(s3, 3);hashMap.put(s4, 4);hashMap.put(s5, 5);hashMap.put(s6, 6);Set<Map.Entry<Student, Integer>> entries = hashMap.entrySet();for (Map.Entry<Student, Integer> entry : entries) {System.out.println(entry.getKey() + ":" + entry.getValue());}/** Student{name='钟馗', age=22}:6* Student{name='刘禅', age=19}:2* Student{name='蔡文姬', age=21}:4* Student{name='朵莉亚', age=20}:3* Student{name='瑶', age=18}:1* Student{name='钟馗', age=22}:5* */}
}
思考:为什么重写了 equals 方法,证明 5,6 两个 key 相同,但仍然会存储呢?
2.Hash 表存储原理
- 先调用 key 的 hashCode 方法,生成哈希值;
- 将哈希值对数组长度进行取模运算,即【 哈希值 % 数组长度 】,计算出对应的索引值;
- 如果索引处没有存储元素,则将键值对封装为 Node 对象,然后存入该位置中;
- 如果索引处有元素,则遍历整个单链表。若遍历出节点的 key 与添加键值对的 key 相同,则做覆盖操作;若遍历出无 key 相同,则把添加的键值对封装成 Node 对象,然后插入单链表的末尾;
- 产生哈希冲突的情况:
- 不同的 key 获得相同的哈希值;
- 通过 key 得到不同的哈希值,但是通过【 哈希值 % 数组长度 】得到的结果相同。
- 一个好的哈希函数,是散列分布均匀的;
- 解决哈希冲突:将冲突的结点挂在同一链表上或同一红黑树上。
3.重写 hashCode 和 equals 方法
对于 1 中的思考,应该从以下方面考虑。
如果调用 equals 方法,结果是 true,说明两个对象相同,但仍然存储说明没有发生哈希碰撞。由 2 的 Hash 表存储原理可知,要发生哈希碰撞有两种情况,此时应该要两个相同 key 生成的哈希值相同,才能避免重复存储。所以需要同时重写 hashCode 方法和 equals 方法。
public class Student {private String name;private int age;public Student(String name, int age) {this.name = name;this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", age=" + age +'}';}@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;Student student = (Student) o;return age == student.age && Objects.equals(name, student.name);}@Overridepublic int hashCode() {return Objects.hash(name, age);}
}
public class HashMapTest {public static void main(String[] args) {HashMap<Student, Integer> hashMap = new HashMap<>();Student s1 = new Student("瑶", 18);Student s2 = new Student("刘禅", 19);Student s3 = new Student("朵莉亚", 20);Student s4 = new Student("蔡文姬", 21);Student s5 = new Student("钟馗", 22);Student s6 = new Student("钟馗", 22);System.out.println(s5.equals(s6)); // trueSystem.out.println(s5.hashCode()); // 37783039System.out.println(s6.hashCode()); // 37783039System.out.println(s5.hashCode() % 16); // 15System.out.println(s6.hashCode() % 16); // 15hashMap.put(s1, 1);hashMap.put(s2, 2);hashMap.put(s3, 3);hashMap.put(s4, 4);hashMap.put(s5, 5);hashMap.put(s6, 6);Set<Map.Entry<Student, Integer>> entries = hashMap.entrySet();for (Map.Entry<Student, Integer> entry : entries) {System.out.println(entry.getKey() + ":" + entry.getValue());}/** Student{name='瑶', age=18}:1* Student{name='刘禅', age=19}:2* Student{name='蔡文姬', age=21}:4* Student{name='朵莉亚', age=20}:3* Student{name='钟馗', age=22}:6* */}
}
4.key 为 null
key 可以为 null,但只能存在一个,多者会被覆盖。
public class HashMapTest {public static void main(String[] args) {HashMap<Integer, String> hashMap = new HashMap<>();hashMap.put(null,"齐");hashMap.put(1,"楚");hashMap.put(2,"秦");hashMap.put(3,"燕");hashMap.put(4,"赵");hashMap.put(5,"魏");hashMap.put(null,"韩");System.out.println(hashMap); // {null=韩, 1=楚, 2=秦, 3=燕, 4=赵, 5=魏}}
}
5.jdk 8 后新特性
(1)初始化时
- jdk 8 之前,构造方法执行时初始化 table 数组;
- jdk 8 之后,第一次调用 put 方法时初始化 table 数组。
(2)插入
- jdk 8 之前,头插法;
- jdk 8 之后,尾插法。
(3)数据结构
jdk 8 之前,是数组与单向链表的结合;
jdk 8 之后,是数组、单向链表和红黑树的结合;
最开始使用单向链表解决哈希冲突。若 结点数 >= 8 且 table 长度 >= 64,则单向链表转换为红黑树;
当删除红黑树上的结点时,当 结点数 <= 6 时,红黑树转换为单向链表。
6.容量
- 默认情况下,数组长度为 16;
- HashMap 容量永远是 2 的次幂,例如:2、4、8、16、32、64……。原因有两点:为了提高哈希计算效率和减少哈希冲突,让散列分布更均匀;
- 哈希表中元素越来越多时,因为数组长度固定,所以散列碰撞的几率也随之增大,从而导致单链表过长,降低了哈希表的性能;
- 当执行 put 操作时,如果 HashMap 中存储元素的个数超过【数组长度 * 负载因子】的结果(负载因子即 loadFactor,默认值一般为 0.75 ),则需要扩容;
- 扩容即把数组大小扩大一倍,然后遍历哈希表中元素,将其重新均匀分散;
- 扩容是一个非常消耗性能的操作,所以建议预测需要存储元素的个数;
- 例如:设置哈希表的容量为 15,实际创建完 HashMap对象后,实际容量是 12 。因为 HashMap 的容量永远为 2 的次幂,最接近 15 的是 16,16 * 0.75 = 12 。
二、LinkedHashMap
1.说明
- 是 HashMap 的子类,两者用法基本一致;
- 但 LinkedHashMap 是有序不可重复的(插入顺序与读取顺序一致且不可重复);
- 通过双向链表记录来保证插入顺序;
- 效率较 HashMap 低一些;
- 其 key 也需要同时重写 equals 和 hashCode 方法;
- 底层是哈希表与双向链表结合的数据结构;
- key 可以为 null,但只能存在一个,多者会被覆盖。
2.实例
public class LinkedHashMapTest {public static void main(String[] args) {LinkedHashMap<Integer, String> linkedHashMap = new LinkedHashMap<>();linkedHashMap.put(1, "小禾");linkedHashMap.put(2, "小明");linkedHashMap.put(3, "小红");linkedHashMap.put(4, "小雯");linkedHashMap.put(5, "小凡");linkedHashMap.put(5, "小州");Set<Map.Entry<Integer, String>> entries = linkedHashMap.entrySet();for (Map.Entry<Integer, String> entry : entries) {System.out.println(entry.getKey() + ":" + entry.getValue());}/** 1:小禾* 2:小明* 3:小红* 4:小雯* 5:小州* */}
}
三、Hashtable
1.说明
- 和 HashMap 一样,底层也是哈希表;
- Hashtable 是线程安全的,方法上都有 synchronized 关键字;
- 初始化容量是 11,默认负载因子是 0.75;
- 扩容后的容量是原容量的 2 倍;
- key 和 value 都不能是 null 。
2.实例
public class HashtableTest {public static void main(String[] args) {Hashtable<Integer, String> hashtable = new Hashtable<>();hashtable.put(1, "老张");hashtable.put(2, "老王");hashtable.put(3, "老李");hashtable.put(4, "老赵");hashtable.put(5, "老孙");
// hashtable.put(null, "老冯"); // java.lang.NullPointerException
// hashtable.put(6, null); // java.lang.NullPointerExceptionSet<Map.Entry<Integer, String>> entries = hashtable.entrySet();for (Map.Entry<Integer, String> entry : entries) {System.out.println(entry.getKey() + ":" + entry.getValue());}/** 5:老孙* 4:老赵* 3:老李* 2:老王* 1:老张* */}
}
3.特有方法
ublic class HashtableTest {public static void main(String[] args) {Hashtable<Integer, String> hashtable = new Hashtable<>();hashtable.put(1, "老张");hashtable.put(2, "老王");hashtable.put(3, "老李");/*** 特有方法*/// 获取所有的keyEnumeration<Integer> keys = hashtable.keys();while (keys.hasMoreElements()) {System.out.print(keys.nextElement() + "\t");}// 3 2 1System.out.println();// 获取所有的valueEnumeration<String> values = hashtable.elements();while (values.hasMoreElements()) {System.out.print(values.nextElement() + "\t");}// 老李 老王 老张}
}
四、Properties
1.说明
- 属性类;
- 继承 Hashtable,也是一个线程安全的 Map 集合;
- 一般和 java 程序中属性配置文件联合使用;
- 该类不支持泛型,key 和 value 都是固定的 String 类型。
2.实例
public class PropertiesTest {public static void main(String[] args) {Properties p = new Properties();p.setProperty("name", "张三");p.setProperty("age", "18");p.setProperty("sex", "男");p.setProperty("address", "北京");System.out.println(p.getProperty("name")); // 张三System.out.println(p.getProperty("age")); // 18System.out.println(p.getProperty("sex")); // 男System.out.println(p.getProperty("address")); // 北京Enumeration<?> enumeration = p.propertyNames();while (enumeration.hasMoreElements()) {String name = (String) enumeration.nextElement();String value = p.getProperty(name);System.out.println(name + ":" + value);}/** address:北京* age:18* name:张三* sex:男* */}
}相关文章:
Java基础关键_021_集合(五)
目 录 一、HashMap 1.key 存储自定义类型 2.Hash 表存储原理 3.重写 hashCode 和 equals 方法 4.key 为 null 5.jdk 8 后新特性 (1)初始化时 (2)插入 (3)数据结构 6.容量 二、LinkedHashMap 1.…...
mcp 是一种什么协议,怎么构建mcpserver,怎么实现多智能体的调用
MCP(Message Control Protocol)是一种用于分布式系统中多智能体通信的协议框架,特别适合于构建多智能体系统。下面我将介绍MCP协议的基本原理以及如何构建MCP服务器和实现多智能体调用。 MCP协议概述 MCP协议主要用于定义智能体之间如何交换…...
Nginx的流式响应配置详解
现在大模型场景繁多,项目中涉及nginx转发大模型的流式数据时,需配置nginx的转发策略: location /streaming {proxy_pass http://backend_server;proxy_cache off; # 关闭缓存proxy_buffering off; # 关闭代理缓冲chunked_transfer_encoding …...
windows10 清理 C 盘
系统自带功能清理 磁盘清理:右键单击 C 盘,选择“属性” ,点击“磁盘清理” ,系统会开始扫描可清理的文件,如临时文件、回收站文件、系统更新备份文件等。扫描完成后,勾选想要清理的文件类型,点…...
浅谈Linux中的Shell及其原理
浅谈Linux中的Shell及其原理 Linux中Shell的运行原理github地址前言一、Linux内核与Shell的关系1.1 操作系统核心1.2 用户与内核的隔离 二、Shell的演进与核心机制2.1 发展历程2.2 核心功能解析2.3 shell的工作流程1. 用户输入命令2. 解析器拆分指令3. 扩展器处理动态内容变量替…...
ARM内部寄存器与常用汇编指令(ARM汇编)
1 地址空间&RISC与CISC CISC:复杂指令集计算机 RISC:精简指令集计算机 RISC 与 CISC 的比较 2 ARM内部寄存器 3 ARM汇编概述 RISC精简指令可以大致分为几类: 1.内存读写 2.运算 3.跳转/分支 4.比较 而指令的集合就称之为“指令集”…...
【QT5 Widgets示例】Model/View编程初探
文章目录 Model/ViewModel/View编程的优点常见Model类和View类Model/View应用程序示例只读的表格修改文本外观显示变化的数据设置表格标头可编辑视图示例树结构视图示例获取视图选中项 Model/View Model/View编程的优点 Model/View编程介绍:https://doc.qt.io/qt-…...
一键优化右键菜单,高效又清爽!
打工人们你们好!这里是摸鱼 特供版~ 电脑右键菜单杂乱无章,常用功能被淹没?图标显示异常、打印出错让人手足无措?别担心,Easy Context Menu来帮你!这是一款右键菜单管理工具,能快速清理不必要的…...
排查数据库的正在执行的占用的慢sql语句,可以查看生产的执行sql语句时间
1. 生产报错异常: org.springframework.transaction.CannotCreateTransactionException: Could not open JDBC Connection for transaction; nested exception is java.sql.SQLException: master - Interrupted during connection acquisition2.在数据库执行查询生…...
Java泛型程序设计使用方法
Java泛型程序设计是Java语言中一项强大的特性,它允许你编写更加通用和类型安全的代码。以下是Java泛型程序设计的使用方法和技巧: 1. 基本概念 泛型类:可以定义一个类,其中的某些类型是参数化的。 public class Box<T> {pr…...
成绩排序(结构体排序)
成绩排序 #include<stdio.h> #include<stdlib.h> struct student{char name[50];int score;int order; }; int flag; int cmp(const void *a,const void *b){struct student *s1(struct student*)a;struct student *s2(struct student*)b;if(s1->scores2->…...
【redis】lua脚本
在分布式系统与高并发架构的战场中,开发者们始终在与两个永恒的命题博弈:数据一致性与系统性能。当我们试图用Redis构建高速缓存、实现分布式锁或设计秒杀系统时,往往会陷入这样的困境——如何在保证原子性的同时,避免网络往返带来…...
Oracle中的INHERIT PRIVILEGES权限
Oracle中的INHERIT PRIVILEGES权限 存储过程和用户函数的AUTHID属性调用者权限vs定义者权限一个简单的示例INHERIT PRIVILEGES权限的含义INHERIT PRIVILEGES权限的安全隐患注意到Oracle 19c数据库中有如下权限信息: SQL> select grantor,grantee,table_name,privilege fro…...
Kafka相关的面试题
以下是150道Kafka相关的面试题及简洁回答: Kafka基础概念 1. 什么是Kafka? Kafka是一个分布式、可扩展、容错的发布-订阅消息系统,最初由LinkedIn开发,现为Apache项目。它适用于高吞吐量的场景,如大数据处理和实时数据…...
OpenHarmony-XTS测试
OpenHarmony-XTS测试 OpenHarmony-XTS测试环境搭建测试准备开始运行PS OpenHarmony-XTS测试 针对OpenHarmony版本进行XTS测试使用记录。 windows环境。 以acts套件为例。 环境搭建 获取测试套件,两种方法 1)官网下载:https://www.openharm…...
【物联网-WIFI】
物联网-WIFI ■ ESP32-C3-模块简介■ ESP32-C3-■ ESP32-C3-■ WIFI-模组■ WIFI-■ WIFI- ■ ESP32-C3-模块简介 ■ ESP32-C3- ■ ESP32-C3- ■ WIFI-模组 ■ WIFI- ■ WIFI-...
作业9 (2023-05-05 数组的定义和初始化)
第1题/共11题【单选题】 关于一维数组初始化,下面哪个定义是错误的?( ) A.int arr[10] = {1,2,3,4,5,6}; B.int arr[] = {1,2,3,4,5,6}; C.int arr[] = (1,2,3,4,5,6); D.int arr[10] = {0}; A:正确,10个int的一段连续空间,前6个位置被初始化为1,2,3,4,5,6,其他…...
C语言中的流程控制语句
一.流程控制语句的分类: 1.顺序结构 概念:从上往下依次执行,也是程序默认的执行顺序 2.分支结构 概念:程序在执行的过程中出现了岔路(我们只能选择一条支线进行执行) (1).if语句…...
linux常用基本指令汇总
文章目录 01. ls指令02. pwd指令03. cd指令04. touch指令05. mkdir指令06. rmdir指令07. rm指令08. man指令09. cp指令10. mv指令11. cat指令11. more指令12. less指令13. head指令14. tail指令15. time指令16. cal指令17. find指令18. grep指令19. zip/unzip指令20.tar指令21.…...
Python 与 JavaScript 交互及 Web 逆向分析全解析
一、引言 在当今数字化时代,软件开发的复杂性和多样性不断增加,不同编程语言之间的交互与协作变得愈发重要。Python 凭借其简洁易读的语法、丰富的库和强大的数据处理能力,在数据科学、自动化脚本编写等领域占据着重要地位。而 JavaScript 作为前端开发的核心语言,以其在网…...
Docker Desktop 安装与使用详解
目录 1. 前言2. Docker Desktop 安装2.1 下载及安装2.2 登录 Docker 账号2.3 进入 Docker Desktop 主界面 3. Docker 版本查看与环境检查3.1 查看 Docker Desktop 支持的 Docker 和 Kubernetes 版本3.2 检查 Docker 版本 4. Docker Hub 和常用镜像管理方式4.1 使用 Docker Hub4…...
鬼泣:移动系统3
能帮到你的话,就给个赞吧 😘 文章目录 run/Sprint混合空间输入:(leanAngle, maxWalkSpeed) 按布尔混合和选择的区别:自动生成过渡动画dead blending:惯性化节点疑问run/Sprint混合空间为什么速度为0时也设置奔跑动画为…...
解决 HTTP 请求中的编码问题:从乱码到正确传输
文章目录 解决 HTTP 请求中的编码问题:从乱码到正确传输1. **问题背景**2. **乱码问题的原因**2.1 **客户端编码问题**2.2 **请求头缺失**2.3 **服务器编码问题** 3. **解决方案**3.1 **明确指定请求体编码**3.2 **确保请求头正确**3.3 **动态获取响应编码** 4. **调…...
golang从入门到做牛马:第二十篇-Go语言接口:行为的“契约”
Go语言接口:行为的“契约” 在Go语言中,接口(interface)是一种非常强大的类型,用于定义行为的集合。接口通过描述类型必须实现的方法,规定了类型的行为契约。Go语言的接口设计简单而功能强大,是实现多态和解耦的重要工具。接下来,让我们一起深入了解Go语言中的接口。 …...
HTML5 Web SQL
HTML5 Web SQL 引言 随着互联网技术的飞速发展,HTML5 作为新一代的网页技术,已经逐渐成为网页开发的主流。在 HTML5 中,Web SQL 是一种轻量级的数据库存储技术,它允许开发者直接在网页中存储数据。本文将详细介绍 HTML5 Web SQL 的概念、特点、应用场景以及使用方法。 一…...
【品铂科技工业生产应用案例解析】
品铂科技(Pinpoint)在工业领域的高精度定位解决方案已广泛应用于电力、钢铁、仓储、化工、地铁等场景,以下为典型应用案例及技术方案: 一、电力行业:上海闵行电厂人员定位 白鹤滩水力发电站 项目需求&#x…...
pjsip dtmf发送和接收(pjsua)
DTMF(双音多频,Dual-Tone Multi-Frequency)是一种用于电话系统的信号技术,通过组合两个不同频率的音频信号来表示数字和符号。以下是DTMF的主要使用背景和应用场景: 电话拨号 DTMF最常见的用途是电话拨号。当用户按下电话键盘上的数字或符号时,电话会生成两个特定频率的音…...
【HarmonyOS Next】鸿蒙应用常规面试题和答辩思路参考
【HarmonyOS Next】鸿蒙应用常规面试题和答辩思路参考 一、充分了解岗位JD要求 根据招聘发布的岗位JD,进行自我匹配分析。了解基本要求和加分项,以及项目节奏和英文要求等。 技术不匹配的点,是否会影响应聘岗位加分项自己是否掌握…...
《计算机图形学》第二课笔记-----二维变换的推导
前言:为什么这么突兀的把这一节内容放在了第二课,第一是因为我急于求成,第二是因为这一章节太重要了,这几乎是二维三维变换的最核心的东西,理解了这一章节内容,后面的就会像打通了任督二脉一样,…...
无需微调的对齐方法URIAL
无需微调的对齐方法URIAL 研究背景与目的:LLMs的对齐调优通常采用监督微调(SFT)和强化学习从人类反馈(RLHF),但LIMA研究表明少量示例的SFT也能实现较好对齐,暗示对齐调优可能存在“表面性质”。本研究旨在探究对齐调优对基础LLMs的具体影响,并提出不依赖SFT或RLHF的对齐…...
