首页 > Java > java教程 > 正文

Java中HashMap的入门使用指南

P粉602998670
发布: 2025-09-20 22:57:01
原创
756人浏览过
HashMap通过哈希机制实现快速存取,核心操作包括put、get、remove及遍历;其性能依赖hashCode和equals的正确实现,需注意键的不可变性、非线程安全、初始容量与负载因子设置,以及null键值的使用风险。

java中hashmap的入门使用指南

HashMap在Java中是一个非常重要的工具,它允许你以键值对(Key-Value Pair)的形式存储数据,并且能以极快的速度根据键来查找对应的值。可以把它想象成一本字典,每个词条(键)都直接指向它的解释(值),而你翻阅起来几乎不需要时间。

使用HashMap其实并不复杂,但要用好它,需要理解它的一些核心操作和特性。

首先,创建一个HashMap实例:

Map<String, Integer> studentScores = new HashMap<>();
登录后复制

这里我们声明了一个键是

String
登录后复制
类型,值是
Integer
登录后复制
类型的HashMap。
Map
登录后复制
是一个接口,
HashMap
登录后复制
是它的一个具体实现。

立即学习Java免费学习笔记(深入)”;

接下来,往HashMap里添加数据,使用

put()
登录后复制
方法:

studentScores.put("张三", 95);
studentScores.put("李四", 88);
studentScores.put("王五", 76);
登录后复制

如果你尝试用相同的键再次

put
登录后复制
一个值,旧的值会被新值覆盖。这是HashMap的一个重要特性:键是唯一的。

获取数据则用

get()
登录后复制
方法,传入键即可:

Integer zhangsanScore = studentScores.get("张三"); // 结果是95
登录后复制

如果键不存在,

get()
登录后复制
会返回
null
登录后复制
。所以在实际开发中,我们通常会检查返回值是否为
null
登录后复制

检查HashMap是否包含某个键或值:

boolean containsLiSi = studentScores.containsKey("李四"); // true
boolean containsScore95 = studentScores.containsValue(95); // true
登录后复制

移除数据使用

remove()
登录后复制
方法:

studentScores.remove("王五");
登录后复制

移除后,"王五"及其分数就不再存在于map中了。

遍历HashMap有几种常见方式。一种是遍历键集,然后通过键获取值:

for (String name : studentScores.keySet()) {
    System.out.println(name + " 的分数是: " + studentScores.get(name));
}
登录后复制

另一种是遍历键值对的Entry集,这种方式效率更高,因为它避免了每次

get()
登录后复制
操作可能带来的二次查找:

import java.util.Map; // 需要导入

for (Map.Entry<String, Integer> entry : studentScores.entrySet()) {
    System.out.println(entry.getKey() + " 的分数是: " + entry.getValue());
}
登录后复制

还有Java 8引入的

forEach
登录后复制
方法,简洁且富有表现力:

studentScores.forEach((name, score) -> System.out.println(name + " 的分数是: " + score));
登录后复制

这些就是HashMap最基础也是最常用的操作了。掌握它们,你就能在很多场景下高效地管理数据。

为什么HashMap的查找速度通常如此之快?它背后的原理是什么?

HashMap之所以能实现近乎常数时间的查找(O(1)),核心在于它的“散列”(Hashing)机制。简单来说,当你

put
登录后复制
一个键值对时,HashMap会先对键进行
hashCode()
登录后复制
计算,得到一个整数值。这个哈希值接着会被用来确定数据在内部数组中的存储位置。如果不同的键计算出相同的哈希值(哈希冲突),HashMap会通过链表或红黑树(Java 8以后)来处理这些冲突,将冲突的元素串联起来。

小门道AI
小门道AI

小门道AI是一个提供AI服务的网站

小门道AI117
查看详情 小门道AI

想象一下,你有一本词典,不是按字母顺序排列,而是根据每个词的“笔画数”来决定它在哪一页。当你想找一个词时,你先数它的笔画,然后直接翻到对应笔画数的页码。即使同一页有很多词(哈希冲突),你只需要在这一小部分词中查找,而不是遍历整本词典。

这个内部数组,我们称之为“桶”(Bucket)。理想情况下,每个桶里只放一个元素,那么查找就是一步到位。但实际情况往往会有冲突,所以桶里可能是一个链表。当链表过长时(默认阈值是8),为了维持查找效率,Java 8后的HashMap会将链表转换为红黑树,这样即使在最坏情况下,查找效率也能保持在O(logN),而不是O(N)。

所以,HashMap的性能高度依赖于键的

hashCode()
登录后复制
方法和
equals()
登录后复制
方法的实现。一个好的
hashCode()
登录后复制
方法能让键均匀分布在各个桶中,减少冲突;而
equals()
登录后复制
方法则用于在哈希冲突发生时,精确判断两个键是否真的相同。如果这两个方法实现不好,HashMap的性能可能会急剧下降,从O(1)退化到O(N),这就有点尴尬了。

HashMap和HashTable、ConcurrentHashMap有什么区别?在什么场景下选择它们?

这三者都是Java中实现键值对存储的类,但它们在线程安全性、性能和一些细节上有所不同。

  • HashMap
    登录后复制
    : 这是我们主要讨论的,它是非线程安全的。这意味着如果在多线程环境下,没有外部同步机制,多个线程同时对同一个HashMap进行读写操作,可能会导致数据不一致甚至程序崩溃(比如
    ConcurrentModificationException
    登录后复制
    )。它的优点是性能高,因为它不需要为线程同步付出额外的开销。

    • 适用场景: 单线程环境,或者在多线程环境下,你能确保对HashMap的所有操作都是在外部同步控制下进行的。追求极致性能时首选。
  • Hashtable
    登录后复制
    : 这是一个历史悠久的类,从Java 1.0就存在了。它和HashMap一样也是键值对存储,但它是线程安全的。Hashtable的所有公共方法都被
    synchronized
    登录后复制
    关键字修饰,这意味着在任何时刻,只有一个线程能访问它的方法。

    • 缺点: 这种粗粒度的同步机制导致了性能瓶颈。当多个线程尝试访问Hashtable时,它们会争夺同一个锁,导致大量的线程等待,性能远不如HashMap。另外,它不允许键或值为
      null
      登录后复制
    • 适用场景: 很少使用,通常建议用
      ConcurrentHashMap
      登录后复制
      替代。如果非要用,可能是为了兼容旧代码,或者在极少数情况下,你确实需要一个简单粗暴的线程安全方案,且对性能要求不高。
  • ConcurrentHashMap
    登录后复制
    : 这是Java并发包(
    java.util.concurrent
    登录后复制
    )提供的一个高性能、线程安全的Map实现。它通过“分段锁”(Segment Locking)或更精细的“CAS操作+Node数组”机制(Java 8以后)来提高并发性能。简单来说,它不是对整个Map加锁,而是对Map的某些部分加锁,允许多个线程同时访问Map的不同部分,从而大大减少了锁竞争。它也允许键和值为
    null
    登录后复制
    (Java 8以后)。

    • 优点: 高度并发,性能优于
      Hashtable
      登录后复制
      ,且线程安全。
    • 适用场景: 多线程环境下的首选。当你需要一个线程安全的键值对存储,并且对性能有较高要求时,
      ConcurrentHashMap
      登录后复制
      是最佳选择。例如,缓存、共享配置等。

所以,选择哪一个,主要看你的应用场景是否涉及多线程以及对性能的要求。单线程用

HashMap
登录后复制
,多线程且追求高性能用
ConcurrentHashMap
登录后复制
Hashtable
登录后复制
基本上可以退休了。

在使用HashMap时,有哪些常见的“坑”或需要注意的问题?

HashMap虽然好用,但用起来也确实有一些需要注意的地方,否则可能会踩到一些意想不到的“坑”。

  1. 键的不可变性(Immutability of Keys): 这是个大坑。如果你用一个可变对象作为HashMap的键,并且在对象放入Map之后又修改了这个对象的某些属性,这可能会导致你再也无法通过

    get()
    登录后复制
    方法找到它。因为修改后,这个对象的
    hashCode()
    登录后复制
    值可能已经变了,HashMap会认为它在另一个“桶”里,或者根本找不到。所以,强烈建议使用不可变对象(如
    String
    登录后复制
    ,
    Integer
    登录后复制
    等基本类型包装类)作为HashMap的键
    。如果必须使用自定义对象,请确保该对象的
    hashCode()
    登录后复制
    equals()
    登录后复制
    方法实现正确,并且一旦作为键放入Map,就不要再修改其参与哈希计算的属性。

  2. hashCode()
    登录后复制
    equals()
    登录后复制
    方法的正确实现
    : 前面提到了,HashMap的性能和正确性严重依赖于键的
    hashCode()
    登录后复制
    equals()
    登录后复制

    • 约定: 如果两个对象
      equals()
      登录后复制
      返回
      true
      登录后复制
      ,那么它们的
      hashCode()
      登录后复制
      值必须相等。反之则不要求。
    • 后果: 如果你自定义的类作为键,但没有正确重写这两个方法,或者只重写了一个,就会出现问题。比如,你
      put
      登录后复制
      了一个对象A,然后又创建了一个和A内容完全相同但不是同一个实例的对象B,你期望
      get(B)
      登录后复制
      能取出A的值,但如果
      hashCode()
      登录后复制
      equals()
      登录后复制
      没写好,它可能返回
      null
      登录后复制
  3. 非线程安全问题: 这是最常见的误用。在多线程环境中,未经同步的

    HashMap
    登录后复制
    操作是危险的。比如,一个线程在遍历HashMap,另一个线程同时在修改它(添加、删除元素),这几乎肯定会抛出
    ConcurrentModificationException
    登录后复制
    。即便不抛异常,也可能导致数据丢失或逻辑错误。解决方案是使用
    ConcurrentHashMap
    登录后复制
    ,或者在访问HashMap的代码块外部进行同步(例如使用
    Collections.synchronizedMap()
    登录后复制
    包装,但这通常效率不高)。

  4. 初始容量与负载因子: HashMap在创建时可以指定初始容量(

    initialCapacity
    登录后复制
    )和负载因子(
    loadFactor
    登录后复制
    )。

    • 初始容量: 如果你知道大概会有多少元素,最好设置一个合适的初始容量,这样可以减少HashMap内部的扩容操作,因为扩容是一个比较耗时的过程(需要重新计算所有元素的哈希值并转移)。
    • 负载因子: 默认是0.75。当HashMap中元素的数量达到
      容量 * 负载因子
      登录后复制
      时,HashMap就会进行扩容。如果负载因子设置得太低,会频繁扩容,浪费性能;如果设置得太高,会导致桶中链表过长,增加查找时间。一般情况下,默认值0.75是一个不错的折衷。
  5. null
    登录后复制
    键和
    null
    登录后复制
    :
    HashMap
    登录后复制
    允许使用一个
    null
    登录后复制
    键,并且允许任意数量的
    null
    登录后复制
    值。这与
    Hashtable
    登录后复制
    不同,
    Hashtable
    登录后复制
    不允许
    null
    登录后复制
    键或
    null
    登录后复制
    值。在使用
    null
    登录后复制
    键时要特别小心,因为它可能与
    get()
    登录后复制
    方法返回
    null
    登录后复制
    表示键不存在的情况混淆。

记住这些点,能让你在使用HashMap时少走很多弯路,写出更健壮、更高效的代码。

以上就是Java中HashMap的入门使用指南的详细内容,更多请关注php中文网其它相关文章!

最佳 Windows 性能的顶级免费优化软件
最佳 Windows 性能的顶级免费优化软件

每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。

下载
来源:php中文网
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
最新问题
开源免费商场系统广告
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 意见反馈 讲师合作 广告合作 最新更新 English
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习
PHP中文网抖音号
发现有趣的

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号