HashMap原理详解
一、引言
在Java中,HashMap
是一个非常关键的数据结构,它提供了快速的查找、插入和删除操作。HashMap
的实现基于哈希表,它通过数组和链表(在JDK 1.8中为链表或红黑树)来解决哈希冲突。本文将详细探讨 HashMap
的基本构成、冲突解决机制以及在JDK 1.8中的优化。
二、基本构成
1、数组和链表/红黑树
HashMap
的核心是由数组组成的桶(bucket),每个桶存储一个链表(或红黑树)。当插入一个键值对时,HashMap
会根据键的哈希值找到对应的桶,然后将键值对插入到桶中的链表(或红黑树)。
1.1、数组
数组是 HashMap
的基础结构,它定义了 HashMap
的容量。数组的每个位置称为一个桶(bucket),用于存储键值对。
transient Node<K,V>[] table;
1.2、链表
当多个键的哈希值映射到同一个桶时,这些键值对会以链表的形式存储在该桶中。链表用于解决哈希冲突。
static class Node<K,V> implements Map.Entry<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;
}
public final K getKey() { ... }
public final V getValue() { ... }
public final V setValue(V newValue) { ... }
public final boolean equals(Object o) { ... }
public final int hashCode() { ... }
}
1.3、红黑树
在JDK 1.8中,当链表的长度超过一定阈值(默认为8)时,链表会被转换成红黑树,以提高搜索效率。
static final class TreeNode<K,V> extends LinkedHashMap.Entry<K,V> {
TreeNode<K,V> parent; // 父节点
TreeNode<K,V> left; // 左子树
TreeNode<K,V> right; // 右子树
TreeNode<K,V> prev; // 用于红黑树的前驱节点
boolean red; // 用于红黑树的颜色
TreeNode(int hash, K key, V value, Node<K,V> next) {
super(hash, key, value, next);
}
}
2、哈希函数
HashMap
使用键的 hashCode()
方法计算哈希值,然后通过哈希值和数组长度的位运算得到桶的索引。
final Node<K,V> getNode(int hash, Object key) {
Node<K,V>[] tab; Node<K,V> first, e; int n, i, binCount;
if ((tab = table) != null && (n = tab.length) > 0 &&
(first = tab[i = (n - 1) & hash]) != null) {
if (first.hash == hash && // always check first node
((key == first.key) || (key != null && key.equals(first.key))))
return first;
if ((e = first.next) != null) {
if (first instanceof TreeNode)
return ((TreeNode<K,V>)first).getTreeNode(hash, key, e);
do {
if (e.hash == hash &&
((key == e.key) || (key != null && key.equals(e.key))))
return e;
} while ((e = e.next) != null);
}
}
return null;
}
三、冲突解决与性能优化
1、冲突解决
HashMap
通过链表(或红黑树)解决哈希冲突。当两个键的哈希值相同时,它们会被存储在同一个桶的链表(或红黑树)中。
2、性能优化
- 扩容机制:当
HashMap
中的元素数量超过负载因子与当前容量的乘积时,HashMap
会进行扩容,通常是将容量翻倍。
if ((size >= threshold = (tab == null) ? DEFAULT_INITIAL_CAPACITY : MAXIMUM_CAPACITY))
resize();
- 红黑树:在JDK 1.8中,当链表长度超过阈值时,链表会被转换成红黑树,以优化搜索性能。
四、总结
HashMap
是Java中使用非常广泛的数据结构,它通过数组和链表(或红黑树)的组合提供了高效的数据存储和查询能力。理解其内部实现原理对于优化程序性能和解决实际问题具有重要意义。
版权声明:本博客内容为原创,转载请保留原文链接及作者信息。
参考文章: