HashMap基于数组+链表/红黑树实现,通过哈希算法存储键值对,支持null键和值,不保证顺序;初始容量16,负载因子0.75,扩容时翻倍;需重写hashCode和equals以确保正确性,非线程安全,推荐使用entrySet遍历。

在Java中,HashMap 是最常用的键值对(Key-Value)存储结构之一,属于 java.util 包。它基于哈希表实现,允许使用 null 值和 null 键(但最多只能有一个 null 键),不保证元素的顺序,尤其不保证顺序随时间恒定。
HashMap底层原理简述
HashMap 的底层实现依赖于数组 + 链表(或红黑树)的结构:
- 数组(Node[] table):HashMap 内部维护一个 Node 数组,每个位置称为“桶”(bucket)。通过 key 的 hash 值确定该键值对应存放在哪个桶中。
- 链表与红黑树:当多个 key 的 hash 值映射到同一个桶时,会发生哈希冲突。此时采用链表方式连接多个节点。当链表长度超过 8 且当前数组长度 ≥ 64 时,链表会转换为红黑树,以提高查找效率。
- hash 算法优化:HashMap 对 key 的 hashCode 进行二次哈希扰动,减少碰撞概率。
- 扩容机制:默认初始容量为 16,负载因子为 0.75。当元素数量超过 容量 × 负载因子(即 16×0.75=12)时,触发扩容,容量变为原来的 2 倍。
常用操作示例
以下是一些常见的 HashMap 操作方法及用法说明:
1. 创建 HashMap使用泛型指定键和值的类型:
立即学习“Java免费学习笔记(深入)”;
HashMap2. 添加键值对(put)map = new HashMap<>();
使用 put 方法插入数据,如果键已存在,则替换旧值并返回原值:
map.put("Alice", 25);
map.put("Bob", 30);
map.put("Alice", 26); // 更新 Alice 的年龄,返回 25
3. 获取值(get)
根据 key 获取对应的 value,若 key 不存在则返回 null:
Integer age = map.get("Bob"); // 返回 30
4. 判断键或值是否存在
-
containsKey(key):判断是否包含某个键 -
containsValue(value):判断是否包含某个值
boolean hasAlice = map.containsKey("Alice"); // true
boolean hasAge40 = map.containsValue(40); // false
5. 删除键值对(remove)
根据 key 删除对应条目,返回被删除的值:
Integer removed = map.remove("Bob"); // 返回 30
6. 遍历 HashMap
推荐使用 entrySet() 遍历键值对:
for (Map.Entryentry : map.entrySet()) { System.out.println(entry.getKey() + ": " + entry.getValue()); }
也可以只遍历 keySet 或 values:
// 遍历所有键
for (String key : map.keySet()) {
System.out.println(key);
}
// 遍历所有值
for (Integer value : map.values()) {
System.out.println(value);
}
注意事项与性能建议
-
key 类型需正确重写 hashCode 和 equals:如果使用自定义对象作为 key,必须重写
hashCode()和equals()方法,否则可能导致 put 和 get 失效。 -
避免频繁扩容:如果预知数据量较大,建议初始化时指定容量,如
new HashMap(32),减少 rehash 开销。 - 非线程安全:HashMap 不是线程安全的。多线程环境下应使用 ConcurrentHashMap 或进行外部同步。
- null 的处理要小心:虽然支持 null 键和 null 值,但在 get 操作中无法区分是 key 不存在还是值为 null,可配合 containsKey 使用。










