Java HashMap详解

HashMap是Java中一个经典的数据结构,它实现了Map接口,提供了一种键值对的映射关系。因为它的高效性和易用性,HashMap在Java编程中被广泛使用。

一、HashMap的基本概念

HashMap是一个散列表,它存储的是键值对(key-value)映射的数据。

在HashMap中,每个键(key)都是唯一的,对应着一个值(value)。你可以通过键来访问对应的值,类似于字典。在Java中,键和值都可以是任何对象。

二、HashMap的构造方法

HashMap类有多个构造方法,其中比较常用的是以下两个:

/**
 * 创建一个空的HashMap
 */
HashMap()

/**
 * 创建一个具有指定初始容量和默认负载因子(0.75)的HashMap
 *
 * @param initialCapacity 初始容量
 */
HashMap(int initialCapacity)

第一个构造方法用来创建一个空的HashMap。第二个构造方法用来创建一个具有指定初始容量(initialCapacity)的HashMap。初始容量指的是HashMap能够容纳键值对的数量,当HashMap中存储的键值对数量超过了这个值,HashMap会自动进行扩容。

三、HashMap的常用方法

HashMap提供了许多常用的方法,下面介绍一些比较重要的方法:

1、put()

put()方法用来将键值对插入到HashMap中。如果给定的键已经存在了,则它对应的值会被更新为新的值。

/**
 * 将指定的键和值插入到HashMap中,如果键已经存在,则更新对应的值
 * @param key 键
 * @param value 值
 * @return 如果之前存在对应的值,则返回旧的值,否则返回null
 */
V put(K key, V value)

2、get()

get()方法用来根据键来获取对应的值。

/**
 * 根据键来获取对应的值
 * @param key 键
 * @return 值
 */
V get(Object key)

下面是一个简单的示例:

HashMap<String, Integer> map = new HashMap<>();
map.put("apple", 1);
map.put("banana", 2);
map.put("orange", 3);
System.out.println(map.get("apple"));
System.out.println(map.get("banana"));
System.out.println(map.get("orange"));

输出结果:

1
2
3

3、containsKey()

containsKey()方法用来检查HashMap中是否包含指定的键。

/**
 * 检查HashMap中是否包含指定的键
 * @param key 键
 * @return 如果包含指定的键,则返回true,否则返回false
 */
boolean containsKey(Object key)

4、containsValue()

containsValue()方法用来检查HashMap中是否包含指定的值。

/**
 * 检查HashMap中是否包含指定的值
 * @param value 值
 * @return 如果包含指定的值,则返回true,否则返回false
 */
boolean containsValue(Object value)

5、remove()

remove()方法用来根据指定的键来删除对应的键值对。

/**
 * 根据指定的键来删除对应的键值对
 * @param key 键
 * @return 如果存在对应的值,则返回被删除的值,否则返回null
 */
V remove(Object key)

6、keySet()

keySet()方法用来获取HashMap中所有键的集合。

/**
 * 获取HashMap中所有键的集合
 * @return 键的集合
 */
Set<K> keySet()

下面是一个简单的示例:

HashMap<String, Integer> map = new HashMap<>();
map.put("apple", 1);
map.put("banana", 2);
map.put("orange", 3);
Set<String> keys = map.keySet();
for (String key : keys) {
    System.out.println(key + " -> " + map.get(key));
}

输出结果:

banana -> 2
orange -> 3
apple -> 1

四、HashMap的扩容机制

HashMap的扩容机制非常重要。当HashMap中的键值对数量达到一定程度时,HashMap会自动进行扩容,这是为了保证HashMap的高效性。HashMap的扩容机制遵循以下两个原则:

1、容量(capacity)总是2的幂次方

HashMap的容量总是2的幂次方,这是为了方便计算哈希值。当你向HashMap中插入一个键值对时,HashMap会根据键的哈希值来计算该键值对应该放在哪个位置。如果HashMap的容量不是2的幂次方,那么计算哈希值的时候需要进行额外的处理,这会降低HashMap的效率。

2、负载因子(load factor)默认为0.75

负载因子决定了HashMap何时需要进行扩容。负载因子默认为0.75,这意味着当HashMap中存储的键值对数量达到总容量的75%时,HashMap就会进行扩容。这样做的好处是可以保证HashMap的效率,即当HashMap中存储的键值对数量不多时,HashMap的容量也不会过大,从而提高HashMap的检索效率。

下面是一个HashMap扩容的示例:

HashMap<Integer, Integer> map = new HashMap<>();
System.out.println(map.size());
for (int i = 0; i < 30; i++) {
    map.put(i, i);
    System.out.println("put:" + i);
}
System.out.println(map.size());

输出结果:

0
put:0
put:1
put:2
put:3
put:4
put:5
put:6
put:7
put:8
put:9
put:10
put:11
put:12
put:13
put:14
put:15
put:16
put:17
put:18
put:19
put:20
put:21
put:22
put:23
put:24
put:25
put:26
put:27
put:28
put:29
32

从上面的代码可以看出,初始容量为16的HashMap存储了30个键值对后,容量自动扩容为32。

五、HashMap和线程安全性

HashMap并不是线程安全的。如果多个线程同时读写一个HashMap,有可能会出现数据不一致的情况。如果需要在多线程环境中使用HashMap,可以考虑使用ConcurrentHashMap。

下面是一个对HashMap进行读写操作的示例:

HashMap<Integer, Integer> map = new HashMap<>();
ExecutorService executorService = Executors.newCachedThreadPool();
for (int i = 0; i < 1000; i++) {
    executorService.submit(() -> {
        for (int j = 0; j < 1000; j++) {
            map.put(j, j);
            System.out.println(map.get(j));
        }
    });
}
executorService.shutdown();

输出结果中可能会存在重复的数字,这是因为多个线程同时进行读写操作导致的。

下面是对ConcurrentHashMap进行读写操作的示例:

ConcurrentHashMap<Integer, Integer> map = new ConcurrentHashMap<>();
ExecutorService executorService = Executors.newCachedThreadPool();
for (int i = 0; i < 1000; i++) {
    executorService.submit(() -> {
        for (int j = 0; j < 1000; j++) {
            map.put(j, j);
            System.out.println(map.get(j));
        }
    });
}
executorService.shutdown();

输出结果中不会存在重复的数字,因为ConcurrentHashMap是线程安全的。

六、HashMap的性能分析

HashMap的性能非常优秀,它的常见操作的时间复杂度为O(1)。但是在实际使用中,我们需要注意其扩容机制可能会带来的性能影响。

下面是一个对HashMap进行性能测试的示例:

long start, end;
HashMap<Integer, Integer> map = new HashMap<>();
Random rand = new Random();
start = System.nanoTime();
for (int i = 0; i < 100000; i++) {
    map.put(i, rand.nextInt());
}
end = System.nanoTime();
System.out.println("插入100000个键值对,耗时:" + (end - start) + "ns");

start = System.nanoTime();
for (int i = 0; i < 100000; i++) {
    map.get(rand.nextInt(100000));
}
end = System.nanoTime();
System.out.println("随机访问100000个键值对,耗时:" + (end - start) + "ns");

在我的电脑上,上面的代码的输出结果大概如下:

插入100000个键值对,耗时:10503887ns
随机访问100000个键值对,耗时:68013ns

从上面的代码可以看出,HashMap插入100000个键值对的时间大约为10503887纳秒,随机访问100000个键值对的时间大约为68013纳秒。

七、总结

本文从HashMap的基本概念、构造方法、常用方法、扩容机制、线程安全性和性能分析等多个方面对HashMap进行了详细的介绍。HashMap是Java中一个经典的数据结构,它的高效性和易用性使得它在Java编程中被广泛使用。在使用HashMap时,我们需要注意其扩容机制可能会带来的性能影响,并且需要考虑线程安全性问题。

原创文章,作者:小蓝,如若转载,请注明出处:https://www.506064.com/n/180216.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
小蓝的头像小蓝
上一篇 2024-11-22 05:11
下一篇 2024-11-22 05:11

相关推荐

  • 寂静岭剧情详解(寂静岭结局解析)

    但到了表世界,就是灰蒙蒙的景象。到了里世界,就是丧尸蟑螂怪的天下了。而处于这三个世界的人又看不到彼此,这就是为什么当男主和女主在同一个空间与时间的时候却不能相 当清楚了表里世界观后…

  • mysql-connector-java.jar是什么

    一、介绍 MySQL Connector/J是MySQL官方提供的Java语言访问MySQL数据库的驱动程序,是Java语言开发MySQL应用程序的必备组件之一。MySQL Con…

    编程 2025-01-13
  • Oracle登录sys用户详解

    一、oracle登录sys用户口令 1、在oracle中,sys用户是系统管理员,登录sys用户需要输入口令。 2、默认情况下,oracle安装后sys用户不需要输入口令登录系统。…

    编程 2025-01-13
  • Java@Link开发:打造高效稳定的Web应用程序

    一、为什么选择Java@Link Java@Link是一种基于JavaEE和Spring技术栈的企业级开发框架,它具有以下几个优势: 1. 开发效率高 Java@Link提供了许多…

    编程 2025-01-13
  • java下载功能,java下载功能怎么实现的

    本文目录一览: 1、怎样编一个能实现文件下载功能的JAVA程序 2、java下载功能实现 3、java 如何实现下载功能 4、java如何实现文件上传和下载的功能 5、Java如何…

    编程 2025-01-13
  • Python CSV模块详解

    Python是一种广泛使用的高级编程语言,常被应用于Web开发、数据分析、人工智能等领域。在Python中,有许多内置模块可以使用,其中一个非常常见且实用的模块就是CSV模块。在本…

    编程 2025-01-13
  • MasterAuth详解

    一、MasterAuth EOF MasterAuth是一种基于Redis的轻量级认证鉴权系统,可以为不同的应用和服务提供安全认证和访问控制。它通过Redis作为数据存储,支持多种…

    编程 2025-01-13
  • Idea更改JDK详解

    一、Idea更改JDK版本 Idea是一款非常常用的Java开发工具,使用时需要配置对应的JDK版本。在项目开发的不同阶段,我们可能需要更换JDK版本。 更改JDK版本的步骤如下:…

    编程 2025-01-13
  • CRC算法详解

    一、CRC算法概述 CRC(Cyclic Redundancy Check) 算法是一种数据校验算法,广泛应用于数据通信领域。该算法通过将消息转换成多项式,并使用一些预定义的多项式…

    编程 2025-01-13
  • Android:tint详解

    一、概述 Android:tint是一个非常有用的属性,它可以让我们在不改变原有资源的情况下改变资源的颜色,比如ImageView和Button等组件的图标或背景。在UI设计中,这…

    编程 2025-01-13

发表回复

登录后才能评论