深入剖析HashMap:理解Hash、底层实现与扩容机制

简介: 深入剖析HashMap:理解Hash、底层实现与扩容机制

一、简单叙述

HashMap是Java中常用的一种数据结构,它以键值对的形式存储数据,具有高效的查找、插入和删除操作。本文将详细介绍HashMap的底层实现原理,包括哈希技术、底层数据结构和扩容机制,帮助读者深入理解HashMap的工作原理。

HashMap是Java集合框架中的一部分,它基于哈希表实现,允许使用任何对象作为键来存储和检索值。HashMap是非同步的,如果多个线程同时访问并至少有一个线程修改了HashMap,则必须在外部同步。

底层实现

public class HashMap<K, V> {
    static class Node<K, V> {
        final int hash;
        final K key;
        V value;
        Node<K, V> next;
        Node(int hash, K key, V value, Node<K, V> next) {
            this.hash = hash;
            this.key = key;
            this.value = value;
            this.next = next;
        }
    }
    // 其他代码...
}

二、哈希技术

  1. 哈希函数

哈希函数是一种将任意长度的数据映射为固定长度数据的算法。在HashMap中,哈希函数的作用是将键映射到一个索引位置,以便快速查找和存储键值对。

  1. 哈希冲突

当两个或多个键的哈希值相同时,它们将映射到同一个索引位置,这种现象称为哈希冲突。HashMap使用链表和红黑树来解决哈希冲突,确保每个索引位置只存储一个键值对。

三、HashMap的底层实现

  1. 数据结构

HashMap底层采用数组+链表+红黑树的数据结构实现。数组是HashMap的主体,用于存储键值对;链表用于解决哈希冲突;红黑树是在链表长度超过一定阈值(默认为8)时,将链表转换为红黑树,以提高查找效率。

  1. 存储结构

HashMap的存储结构是一个Node类型的数组,Node是一个内部类,实现了Map.Entry接口。每个Node对象包含四个属性:key(键)、value(值)、hash(哈希值)和next(指向下一个Node的指针)。当发生哈希冲突时,新的键值对将被添加到链表中。

四、扩容机制

  1. 什么时候扩容

当HashMap中的元素数量达到数组大小的加载因子(默认为0.75)时,会触发扩容操作。加载因子是一个阈值,用于控制数组的大小和扩容的时机。加载因子越大,数组的空间利用率越高,但冲突的概率也越大;加载因子越小,数组的空间利用率越低,但冲突的概率也越小。因此,选择合适的加载因子可以平衡空间利用率和冲突概率。

  1. 如何扩容

扩容操作包括两个步骤:创建新的数组和重新计算键的哈希值。首先,HashMap会创建一个新的数组,其大小是原数组大小的两倍。然后,HashMap会遍历原数组中的每个元素,重新计算键的哈希值,并将键值对存储到新的数组中。在重新计算哈希值时,HashMap会使用一个特殊的算法来确保相同的键在新的数组中仍然具有相同的哈希值。这个算法称为“再哈希”。

void resize(int newCapacity) {
    Node<K, V>[] oldTable = table;
    int oldCapacity = oldTable.length;
    if (oldCapacity == MAXIMUM_CAPACITY) {
        threshold = Integer.MAX_VALUE;
        return;
    }
    Node<K, V>[] newTable = new Node[newCapacity];
    transfer(newTable);
    table = newTable;
    threshold = (int) (newCapacity * loadFactor);
}

五、总结

本文详细介绍了HashMap的底层实现原理,包括哈希技术、底层数据结构和扩容机制。HashMap是一种高效的数据结构,它使用哈希表实现键值对的存储和检索操作。通过深入了解HashMap的工作原理,我们可以更好地理解和使用它来解决实际问题。在实际开发中,我们需要根据具体情况选择合适的加载因子和初始容量来创建HashMap实例以提高性能和效率。

相关文章
|
25天前
|
存储 Java
HashMap的扩容机制是怎样的
在Java中,HashMap 是一个基于哈希表的键值对集合,它以其高效的存取性能而广泛使用。HashMap 的扩容机制是其性能优化的关键部分,本文将详细介绍这一机制的工作原理和过程。
|
2月前
|
存储 Java 程序员
Java面试加分点!一文读懂HashMap底层实现与扩容机制
本文详细解析了Java中经典的HashMap数据结构,包括其底层实现、扩容机制、put和查找过程、哈希函数以及JDK 1.7与1.8的差异。通过数组、链表和红黑树的组合,HashMap实现了高效的键值对存储与检索。文章还介绍了HashMap在不同版本中的优化,帮助读者更好地理解和应用这一重要工具。
66 5
|
2月前
|
存储
让星星⭐月亮告诉你,HashMap的put方法源码解析及其中两种会触发扩容的场景(足够详尽,有问题欢迎指正~)
`HashMap`的`put`方法通过调用`putVal`实现,主要涉及两个场景下的扩容操作:1. 初始化时,链表数组的初始容量设为16,阈值设为12;2. 当存储的元素个数超过阈值时,链表数组的容量和阈值均翻倍。`putVal`方法处理键值对的插入,包括链表和红黑树的转换,确保高效的数据存取。
63 5
|
2月前
|
存储
HashMap扩容机制
【10月更文挑战第11天】 `HashMap`的扩容机制是其重要特性之一。当容量达到负载因子(默认0.75)时,会触发扩容。扩容时,新容量通常是原容量的两倍,元素需重新哈希并迁移到新数组中。此过程涉及大量计算和迁移,可能影响性能。合理设置初始容量和负载因子,可减少不必要的扩容。在多线程环境中,还需注意线程安全问题。
|
2月前
|
算法 索引
让星星⭐月亮告诉你,HashMap的resize()即扩容方法源码解读(已重新完善,如有不足之处,欢迎指正~)
`HashMap`的`resize()`方法主要用于数组扩容,包括初始化或加倍数组容量。该方法首先计算新的数组容量和扩容阈值,然后创建新数组。接着,旧数组中的数据根据`(e.hash & oldCap)`是否等于0被重新分配到新数组中,分为低位区和高位区两个链表,确保数据迁移时的正确性和高效性。
69 3
|
2月前
|
算法 索引
HashMap扩容时的rehash方法中(e.hash & oldCap) == 0算法推导
HashMap在扩容时,会创建一个新数组,并将旧数组中的数据迁移过去。通过(e.hash & oldCap)是否等于0,数据被巧妙地分为两类:一类保持原有索引位置,另一类索引位置增加旧数组长度。此过程确保了数据均匀分布,提高了查询效率。
45 2
|
2月前
|
存储 算法 安全
HashMap常见面试题(超全面):实现原理、扩容机制、链表何时升级为红黑树、死循环
HashMap常见面试题:红黑树、散列表,HashMap实现原理、扩容机制,HashMap的jd1.7与jdk1.8有什么区别,寻址算法、链表何时升级为红黑树、死循环
|
4月前
|
Java 索引
【Java集合类面试九】、介绍一下HashMap的扩容机制
HashMap的扩容机制包括初始容量16,以2的次方进行扩充,使用负载因子0.75判断是否扩容,以及链表长度达到阈值时转换为红黑树,以优化性能。
【Java集合类面试九】、介绍一下HashMap的扩容机制
|
3月前
|
存储 算法 Java
深入剖析HashMap:理解Hash、底层实现与扩容机制
【9月更文挑战第6天】在Java编程中,`HashMap`是一个常用的数据结构,其高效性和可靠性依赖于深入理解哈希、底层实现及扩容机制。哈希通过散列算法将键映射到数组索引,采用链表或红黑树处理冲突;底层实现结合数组与链表,利用2的幂次方长度加快定位;扩容机制在元素数量超过负载因子与数组长度乘积时触发,通过调整初始容量和负载因子可优化性能。
112 3
|
6月前
|
存储 Java 测试技术
滚雪球学Java(66):Java之HashMap详解:深入剖析其底层实现与源码分析
【6月更文挑战第20天】🏆本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!
49 3
滚雪球学Java(66):Java之HashMap详解:深入剖析其底层实现与源码分析
下一篇
DataWorks