Java 语言 HashMap底层实现 数组+链表+红黑树的结构

Java阿木 发布于 2025-06-25 3 次阅读


摘要:

HashMap是Java中非常常用的一种数据结构,它基于数组+链表+红黑树的结构实现,提供了快速的查找、插入和删除操作。本文将深入解析Java HashMap的底层实现,包括其数组、链表和红黑树的结构,以及它们之间的交互。

一、

HashMap是Java中的一种基于键值对存储的数据结构,它提供了快速的查找、插入和删除操作。HashMap的底层实现采用了数组+链表+红黑树的结构,这种结构使得HashMap在处理大量数据时仍然能够保持较高的性能。

二、数组+链表的结构

1. 数组

HashMap内部使用一个数组来存储元素,数组的每个位置对应一个链表的头节点。数组的长度是2的幂次方,这样可以保证在插入元素时,通过计算hash值与数组长度的模运算,得到一个均匀分布的索引位置。

2. 链表

当两个或多个元素的hash值相同,即发生哈希冲突时,这些元素会被存储在同一个链表中。链表中的元素按照插入顺序排列,这样可以保证元素的顺序性。

三、红黑树的结构

1. 红黑树简介

当链表中的元素数量超过一定阈值时,HashMap会将链表转换为红黑树。红黑树是一种自平衡的二叉搜索树,它通过特定的规则来保证树的平衡,从而提高查找效率。

2. 红黑树的规则

红黑树遵循以下规则:

- 每个节点要么是红色,要么是黑色。

- 根节点是黑色。

- 每个叶子节点(NIL节点)是黑色。

- 如果一个节点是红色的,则它的两个子节点都是黑色的。

- 从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点。

四、HashMap的插入操作

1. 计算hash值

当插入一个键值对时,首先计算键的hash值,然后通过hash值与数组长度的模运算得到数组索引。

2. 插入元素

如果数组索引位置为空,则直接将元素插入到该位置。如果数组索引位置已存在元素,则根据hash值判断是否发生哈希冲突。

3. 处理哈希冲突

如果发生哈希冲突,则将新元素插入到链表的头部或红黑树中。

4. 调整数组长度

当HashMap中的元素数量超过负载因子(load factor)与数组长度的乘积时,需要扩容数组,并将所有元素重新计算hash值后插入到新的数组中。

五、HashMap的查找操作

1. 计算hash值

与插入操作类似,首先计算键的hash值。

2. 查找元素

根据hash值计算数组索引,然后遍历链表或红黑树,查找与给定键匹配的元素。

六、HashMap的删除操作

1. 计算hash值

与查找操作类似,首先计算键的hash值。

2. 删除元素

根据hash值计算数组索引,然后遍历链表或红黑树,找到要删除的元素,并将其从链表或红黑树中移除。

七、总结

Java HashMap的底层实现采用了数组+链表+红黑树的结构,这种结构使得HashMap在处理大量数据时仍然能够保持较高的性能。通过理解HashMap的内部结构和工作原理,我们可以更好地利用它来提高程序的性能。

以下是一个简化的Java HashMap的代码示例:

java

public class HashMap<K, V> {


private static final int DEFAULT_CAPACITY = 16;


private static final float LOAD_FACTOR = 0.75f;


private Entry<K, V>[] table;


private int size;

public HashMap() {


table = new Entry[DEFAULT_CAPACITY];


size = 0;


}

// 省略其他方法...

static class Entry<K, V> {


final K key;


V value;


Entry<K, V> next;


int hash;

Entry(int h, K k, V v, Entry<K, V> n) {


value = v;


next = n;


key = k;


hash = h;


}


}


}


请注意,以上代码仅为简化示例,实际的HashMap实现要复杂得多,包括处理哈希冲突、扩容、红黑树转换等。