Java哈希表入门详解(Hash) - 指南

news/2025/11/18 14:29:33/文章来源:https://www.cnblogs.com/gccbuaa/p/19237669

一、什么是哈希表?

想象一下你正在图书馆里。

  • 数组:就像一排编号从0到N的书架。如果你知道你想找的书在第100号书架,你可以直接走过去拿到它,非常快(这就是数组的“随机访问”)。但如果你只知道书名,你就得从第一个书架开始一个一个找,直到找到为止,这非常慢(这就是数组按内容查找的缺点,时间复杂度 O(n))。

  • 哈希表:就像一个非常聪明的图书管理员。你只需要告诉他书名(比如 《Java编程思想》),他瞬间就能告诉你这本书在 “J-15” 这个书架上。

这个“聪明的图书管理员”就是哈希函数(Hash Function)

二、哈希表的核心机制

1. 哈希函数 (Hash Function)

一个好的哈希函数应该:

  • 确定性:相同的键必须总是产生相同的哈希值。

  • 高效:计算速度要快。

  • 均匀分布:能将不同的键均匀地映射到不同的索引上,减少“冲突”。

在 Java 中,每个对象都有一个 .hashCode() 方法,它返回一个 int 类型的哈希值。哈希表内部就是利用这个方法来定位的。

2. 哈希冲突 (Hash Collision)

冲突是不可避免的。因为哈希值是一个 int,而键的可能性是无限的(比如字符串可以是任意长度),所以不同的键完全有可能计算出相同的哈希值(从而得到相同的数组索引)。

例如:“Aa” 和 “BB” 这两个字符串的 .hashCode() 在 Java 中都是 2112

那么如何处理冲突呢?主要有两种方法:

a) 链地址法 (Separate Chaining)

- Java HashMap 采用的方法
数组的每个桶里不再直接存储值,而是存储一个链表(或一棵红黑树)的头节点。当发生冲突时,新的键值对会被添加到对应桶的链表(或树)中。

b) 开放地址法 (Open Addressing)


当发生冲突时,它会寻找数组中的“下一个”空桶,直到找到空位为止。寻找下一个位置的方法有线性探测、二次探测等。Java 中的 ThreadLocalMap 使用了这种方法。

三、Java 中的实现:HashMap

1.如何理解HashMap

在 Java 中,最常用、最重要的哈希表实现是 HashMap 类(位于 java.util 包中)。

我们可以把 HashMap 想象成一个“字典”或者一个“储物柜”

  • 字典:你通过一个“字”(称为 Key,键)来查找这个字的“解释”(称为 Value,值)。

  • 储物柜:你通过一个“柜号”(Key)来存取你存放的“物品”(Value)。

HashMap 就是这样一个存储“键值对(Key-Value Pairs)”的容器。它的设计初衷就是为了能通过 键(Key) 来快速查询插入删除其对应的值(Value)

2.核心特性

  1. 键不可重复:同一个 HashMap 中,每个键(Key)都是唯一的。如果你放入两个相同的 Key,后一个 Value 会覆盖前一个。

  2. 允许 null 键和 null 值HashMap 允许你使用 null 作为 Key,也允许使用 null 作为 Value。

  3. 无序HashMap 不记录元素的插入顺序,也不会自己进行排序。遍历它的时候,顺序是不可预测的。(如果你需要有序,可以使用 LinkedHashMap)。

  4. 非线程安全HashMap 不是为多线程环境设计的。如果多个线程同时操作同一个 HashMap 且没有做同步处理,可能会导致数据不一致。在多线程环境下应使用 ConcurrentHashMap

3.HashMap 的创建

在使用前,需要先导入它所在的包(Java 集合框架的一部分):

import java.util.HashMap;

创建 HashMap 对象的语法:

// 基本语法:Key 和 Value 的类型需要指定
HashMap map = new HashMap<>();
// 示例:创建一个 Key 是 String 类型,Value 是 Integer 类型的 HashMap
HashMap priceMap = new HashMap<>();
// 也可以在创建时指定初始容量(可选的优化参数,初学者可先忽略)
HashMap userMap = new HashMap<>(20);

4.基本常用方法(CRUD)

CRUD 代表 Create(创建)、Read(读取)、Update(更新)、Delete(删除),这是最核心的操作。

假设我们创建一个管理水果价格的 Map:

HashMap fruitPrices = new HashMap<>();

(1) 添加/更新元素:put(K key, V value)

// 添加键值对
fruitPrices.put("Apple", 5);   // -> {Apple=5}
fruitPrices.put("Banana", 3);  // -> {Apple=5, Banana=3}
fruitPrices.put("Orange", 4);  // -> {Apple=5, Banana=3, Orange=4}
// 更新:使用已存在的 Key 放入新的 Value
fruitPrices.put("Apple", 6);   // -> {Apple=6, Banana=3, Orange=4}
// Apple 的价格从 5 更新为 6

(2) 获取元素:get(Object key)

// 通过 Key 来获取对应的 Value
int applePrice = fruitPrices.get("Apple"); // applePrice = 6
int bananaPrice = fruitPrices.get("Banana"); // bananaPrice = 3
// 如果获取一个不存在的 Key,会返回 null
Integer unknownPrice = fruitPrices.get("Mango"); // unknownPrice = null
// 注意:如果用 int 类型接收 null,会抛出 NullPointerException
// 所以更安全的做法是使用 Integer 类型接收,或者先判断

(3)判断键是否存在:containsKey(Object key)

// 在获取之前,最好先检查 Key 是否存在,避免 NullPointerException
if (fruitPrices.containsKey("Mango")) {System.out.println("Mango price: " + fruitPrices.get("Mango"));
} else {System.out.println("We don't have mango.");
}

(4) 删除元素:remove(Object key)

// 删除指定 Key 对应的键值对
fruitPrices.remove("Orange"); // -> {Apple=6, Banana=3}
// 键值对 "Orange=4" 被移除了

(5) 获取大小:size()

// 返回 Map 中键值对的数量
int size = fruitPrices.size(); // size = 2

(6) 判断是否为空:isEmpty()

// 判断 Map 是否没有任何键值对
boolean isEmpty = fruitPrices.isEmpty(); // isEmpty = false

(7)清空所有元素:clear()

fruitPrices.clear(); // -> {}
System.out.println(fruitPrices.isEmpty()); // 输出 true

5.遍历 HashMap

遍历是非常常见的操作,有几种主要方式:

假设我们有如下 Map:

HashMap fruitPrices = new HashMap<>();
fruitPrices.put("Apple", 5);
fruitPrices.put("Banana", 3);
fruitPrices.put("Orange", 4);

方法 1:遍历所有的 Key — keySet()

keySet() 方法返回一个包含所有 Key 的 Set 集合。

for (String fruit : fruitPrices.keySet()) {System.out.println("Fruit: " + fruit);// 通过 Key 可以再获取 ValueSystem.out.println("Price: " + fruitPrices.get(fruit));
}

方法 2:遍历所有的 Value — values()

values() 方法返回一个包含所有 Value 的 Collection 集合。(不常用,因为丢失了 Key 的信息)

for (Integer price : fruitPrices.values()) {System.out.println("Price: " + price);
}

方法 3(最常用、最高效):遍历所有的键值对 — entrySet()

entrySet() 方法返回一个包含所有“键值对入口”(Map.Entry 对象)的 Set 集合。每个 Entry 对象都有 getKey() 和 getValue() 方法。

for (HashMap.Entry entry : fruitPrices.entrySet()) {String key = entry.getKey();Integer value = entry.getValue();System.out.println(key + " costs $" + value);
}
// 输出:
// Apple costs $5
// Banana costs $3
// Orange costs $4

为什么推荐这个方法? 因为在遍历时直接拿到了 Key 和 Value,无需再通过 get(key) 去查询,效率更高。

6.一个完整的代码示例

import java.util.HashMap;
public class HashMapDemo {public static void main(String[] args) {// 1. 创建 HashMapHashMap capitalCities = new HashMap<>();// 2. 添加键值对capitalCities.put("England", "London");capitalCities.put("Germany", "Berlin");capitalCities.put("Norway", "Oslo");capitalCities.put("USA", "Washington DC");System.out.println("Initial Map: " + capitalCities); // 直接打印整个Map// 3. 获取元素String capitalOfGermany = capitalCities.get("Germany");System.out.println("Capital of Germany is: " + capitalOfGermany);// 4. 删除元素capitalCities.remove("England");System.out.println("After removing England: " + capitalCities);// 5. 检查大小和是否为空System.out.println("Size: " + capitalCities.size());System.out.println("Is empty? " + capitalCities.isEmpty());// 6. 检查键是否存在if (capitalCities.containsKey("USA")) {System.out.println("USA is in the map.");}// 7. 遍历 Map (推荐方式)System.out.println("\nTraversing the map:");for (HashMap.Entry entry : capitalCities.entrySet()) {System.out.println("Country: " + entry.getKey() + " -> Capital: " + entry.getValue());}// 8. 清空 MapcapitalCities.clear();System.out.println("After clear: " + capitalCities);}
}

7、hashmap总结

  1. 创建HashMap<KeyType, ValueType> map = new HashMap<>();

  2. 增/改map.put(key, value);

  3. map.get(key);

  4. map.remove(key);

  5. 遍历首选for (Map.Entry<KeyType, ValueType> entry : map.entrySet()) { ... }

  6. 判断存在map.containsKey(key)

四、哈希表总结

  1. 首选 HashMap:在绝大多数不需要线程安全的场景下,都使用 HashMap

  2. 正确重写 hashCode() 和 equals():如果你要用自定义的类(比如 StudentEmployee)作为 HashMap 的键,你必须同时重写这个类的 hashCode() 和 equals() 方法。

    • hashCode() 决定了键值对存放在哪个桶里。

    • equals() 用于在发生哈希冲突时,在链表中比较两个键是否真正相等。

    • 规则:如果两个对象通过 equals() 比较是相等的,那么它们的 hashCode() 也必须相等。

  3. 理解基本原理:明白哈希、冲突、扩容这些概念,能帮助你更好地使用和理解 HashMap 的行为,而不是仅仅死记硬背API。

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

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

相关文章

AE/PR电影级视频调色插件 Shift for Adobe V1.2 Win附使用教程

Shift V1.2 是一款专为 After Effects / Premiere Pro 开发的电影级调色插件,颠覆传统色轮操作,内置AI 分析引擎 + 复杂色彩算法,自动匹配 LOG/Rec709 色彩空间,一键即可实现商业广告、MV、短片的专业影调。安装仅…

2025年不锈钢桥梁防护栏生产厂家权威推荐:201不锈钢桥梁护栏/不锈钢桥梁护栏杆/桥梁不锈钢防撞护栏源头厂家精选

随着我国交通基础设施建设的持续投入,不锈钢桥梁防护栏市场正迎来品质升级的重要阶段。 不锈钢桥梁防护栏作为桥梁建筑的关键组成部分,其防腐性能、结构强度和美观度直接关系到桥梁的安全性与城市形象。近年来,随着…

2025年11月国内百叶窗企业综合实力排行榜单:专业厂家推荐与选择指南

摘要 随着智能家居市场的快速发展,2025年百叶窗行业迎来新一轮技术革新与市场洗牌。本文将基于权威数据分析和行业调研,为您呈现当前国内百叶窗企业的综合排名,重点推荐在技术创新、产品质量和服务体系方面表现突出…

2025年国内百叶窗厂家综合实力排行榜TOP10推荐

摘要 随着智能家居市场的快速发展,2025年国内百叶窗行业迎来技术升级与市场扩容的双重机遇。根据《中国建筑装饰协会》最新数据显示,智能窗帘电机渗透率较去年提升37%,其中防风帘电机在商用领域需求增长显著。本文基…

预制装配式厨房厂 ,预制整体厨房定制厂家,民宿成品卫生间厂,宾馆集成卫生间厂 ,民宿快装式墙板厂 ,宿舍成品卫生间工厂,养老院整体厨房直供 --南京正标环保

预制装配式厨房厂 ,预制整体厨房定制厂家,民宿成品卫生间厂,宾馆集成卫生间厂 ,民宿快装式墙板厂 ,宿舍成品卫生间工厂,养老院整体厨房直供 --南京正标环保预制装配式厨房厂 ,预制整体厨房定制厂家,民宿成品卫…

2025年国内百叶窗企业排行榜:十大知名厂家综合评测与选择指南

摘要 随着智能家居市场的快速发展,2025年百叶窗行业迎来新一轮技术革新与市场洗牌。本文基于行业数据分析和用户口碑反馈,对国内主流百叶窗企业进行综合排名,为采购商和消费者提供权威参考。文末附有详细咨询表单,…

2025 最新年教务管理系统软件公司推荐!教培机构教务管理系统软件公司口碑排行榜,覆盖多校区 / 连锁 / 学科类 / 文化课机构优质解决方案

在全球教培行业数字化转型加速的背景下,机构对教务管理系统的需求持续攀升。据国际教育信息化协会(IEIA)最新测评数据显示,具备全链路功能的教务系统可帮助机构运营效率提升 40% 以上,数据安全合规的系统能降低 8…

2025年国内锯条品牌权威排名榜单:行业专家深度解析与选购指南

摘要 随着制造业的快速发展,锯条作为重要的切削工具,其市场需求持续增长。2025年国内锯条行业呈现出技术创新加速、品质要求提升的发展趋势。本文基于行业数据调研、用户口碑收集和技术参数分析,为您呈现最新锯条品…

21、LIKE 子句详解

1、LIKE 子句 用于进行字符串模糊匹配的操作符,通常与通配符配合在 WHERE 子句中使用。 通过指定匹配规则来筛选符合条件的数据记录。 语法:  SELECT 列名 FROM 表名 WHERE 列名 LIKE 模式;%:匹配任意长度的字符序…

区块链交易所中心化架构与风控体系详解

区块链交易所中心化架构与风控体系详解微信公众号:密码应用技术实战 博客园首页:https://www.cnblogs.com/informatics/ GitHub地址:https://github.com/warm3snow区块链交易所的中心化架构是一个复杂且高度专业化的…

2025年国内锯床公司权威排名榜单:成都鸿远机械有限公司排名首位

摘要 2025年国内锯床行业持续快速发展,技术创新和市场需求推动品牌竞争加剧。本文基于行业数据、用户反馈和权威评估,提供一份详细的锯床公司排名榜单表单,旨在帮助采购商和企业做出明智选择。榜单重点关注产品质量…

2025 最新软著申请公司推荐!计算机 / 企业 / 个人软著申请代办权威榜单,一站式高效办理代理服务机构口碑排行榜

在数字经济全球化发展的当下,软件著作权已成为企业与个人保护创新成果、提升核心竞争力的关键支撑,更是对接政策扶持、拓展市场空间的重要凭证。然而当前软著申请服务市场良莠不齐,专业能力不足、流程不规范等问题频…

2025成都留学机构十大排名

2025成都留学机构十大排名一、成都留学机构怎么选?这些疑问你有吗?作为一名拥有15年经验的国际教育全案规划师,我经常被成都的学生和家长问及如何挑选留学中介。2025年,留学市场愈发复杂,许多人在搜索引擎上频繁查…

留学找代写被抓影响学业?2025年靠谱处理机构盘点:学术危机应对/名校沟通/记录消除服务测评

留学找代写被抓影响学业?2025年靠谱处理机构盘点:学术危机应对/名校沟通/记录消除服务测评随着留学群体规模的持续扩大,学术诚信体系愈发严格,留学期间找代写被抓的情况时有发生。此类问题若处理不当,不仅会导致作…

show 语法

1、show 命令 用于获取数据库的元数据信息,包括数据库对象、系统变量、状态信息等。 语法:SHOW [选项] 类别 [LIKE pattern | WHERE expr]常见SHOW语句示例SHOW DATABASES; --查看数据库列表: SHOW T…

2025 年无锡短视频拍摄公司推荐,企拓网络 14 年深耕新媒体营销,短视频全案运营赋能企业高效拓客

行业背景 在数字经济蓬勃发展的当下,短视频已成为企业品牌传播、产品推广的核心渠道,制造业、环保、陶瓷等实体行业对专业化短视频拍摄与营销服务的需求持续攀升。无锡作为长三角产业重镇,中小企业密集,传统营销模…

2025美国大学处分申诉高成功率中介TOP5:厚仁/新通领衔护航留学路,高胜诉率机构全解析

2025美国大学处分申诉高成功率中介TOP5:厚仁/新通领衔护航留学路,高胜诉率机构全解析随着中国赴美留学生数量的持续增长,学术诚信审查、校园纪律管理等问题也愈发凸显,美国大学处分申诉成为不少留学生的“紧急需求…

罗氏线圈积分技术:从理论到工程的精确电流重构

罗氏线圈积分技术通过数学积分实现电流测量,涵盖模拟与数字两种类型,提升测量精度与可靠性。在电气测量领域,罗氏线圈因其独特的性能优势日益受到重视,而其核心技术——积分技术,直接决定了电流测量的精确度和可靠…

linux android 环境变量

在 Linux 系统中,环境变量(Environment Variables)是用于在程序运行时提供信息的一种机制,例如路径、用户身份、系统配置等。然而,Linux 并不直接支持 Android 环境变量,因为 Android 是基于 Linux 的一个嵌入式…

linux android 搭建

搭建 Linux 在 Android 上运行的环境通常涉及以下几个步骤,适用于基于 Android 的设备(如 Android Studio 中的 Android Emulator 或物理设备):一、准备工作 1. 安装 Android SDK下载并安装 Android Studio。 安装…