Java集合:双列集合HashMap的概念、特点及使用
字数 1325 2025-08-10 08:28:18
Java HashMap 详解
1. HashMap 概念
HashMap 是 Java 集合框架中 Map 接口的一个实现类,用于存储键值对(key-value)映射关系。它具有以下特性:
- 允许键(key)和值(value)为 null
- 键不能重复(重复的键会覆盖原有值)
- 集合中的元素是无序的
- 非线程安全(不同步)
2. HashMap 底层结构
2.1 存储结构演变
- Java 1.8 之前:数组 + 链表
- Java 1.8 及之后:数组 + 链表 + 红黑树
2.2 核心结构说明
- 数组:HashMap 的主体结构,默认初始容量为 16
- 链表:解决哈希冲突的分支结构
- 红黑树:当链表长度超过阈值(默认为8)时,链表会转换为红黑树以提高查询效率
2.3 存储过程
- 计算键的 hashCode
- 对 hashCode 进行取模运算得到数组下标
- 如果该位置为空,直接存储
- 如果该位置不为空(哈希冲突),则:
- Java 1.8 前:添加到链表末尾
- Java 1.8 后:先添加到链表,链表长度超过8时转换为红黑树
3. HashMap 核心特点
- 高效性:增、删、改、查操作效率较高
- 无序性:元素存储顺序与插入顺序无关
- 动态扩容:当元素数量超过阈值(容量*负载因子,默认0.75)时自动扩容
- 线程不安全:不适合多线程环境使用
4. HashMap 使用示例
4.1 基本使用
Map<String, String> map = new HashMap<>();
map.put("key1", "value1");
map.put("key2", "value2");
String value = map.get("key1");
4.2 自定义对象作为键
当使用自定义对象作为 HashMap 的键时,必须重写 hashCode() 和 equals() 方法:
public class Student {
private String name;
private int age;
// 构造方法、getter/setter 省略
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
return age == student.age && Objects.equals(name, student.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
}
4.3 遍历方式
- 键找值方式:
Set<Student> keySet = map.keySet();
for (Student key : keySet) {
String value = map.get(key);
System.out.println(key + "=" + value);
}
- 键值对对象方式:
Set<Map.Entry<Student, String>> entrySet = map.entrySet();
for (Map.Entry<Student, String> entry : entrySet) {
System.out.println(entry.getKey() + "=" + entry.getValue());
}
5. LinkedHashMap
LinkedHashMap 是 HashMap 的子类,在 HashMap 基础上维护了一个双向链表,可以保持元素的插入顺序或访问顺序。
5.1 特点
- 继承自 HashMap
- 维护插入顺序或访问顺序
- 性能略低于 HashMap(因为要维护链表)
5.2 使用示例
LinkedHashMap<String, String> map = new LinkedHashMap<>();
map.put("马云", "阿里巴巴");
map.put("马化腾", "腾讯");
map.put("李彦宏", "百度");
// 遍历时会按照插入顺序输出
for (Map.Entry<String, String> entry : map.entrySet()) {
System.out.println(entry.getKey() + "=" + entry.getValue());
}
6. 性能优化与注意事项
- 初始容量:预估元素数量设置合理的初始容量,避免频繁扩容
- 负载因子:默认0.75,可根据实际情况调整
- 哈希冲突:良好的 hashCode() 实现可以减少冲突
- 线程安全:多线程环境下应使用 ConcurrentHashMap 或 Collections.synchronizedMap()
- 内存泄漏:避免使用可变对象作为键
7. 常见问题
-
HashMap 和 HashSet 的关系:
- HashSet 底层实际上使用 HashMap 实现
- HashSet 只使用 HashMap 的键,值统一为一个静态常量
-
为什么重写 equals() 必须重写 hashCode():
- 保证相同对象有相同哈希码
- 确保在 HashMap 中能正确找到对象
-
链表转红黑树的阈值:
- 默认是链表长度超过8时转换
- 红黑树退化为链表的阈值是6(避免频繁转换)
HashMap 是 Java 集合框架中非常重要且高效的集合类,合理使用可以大大提高程序处理数据的效率,但需要注意其线程不安全特性和正确实现键对象的 hashCode() 和 equals() 方法。