JAVASE:集合进阶---HashMap集合

在 Java 中,HashMap 是一种基于哈希表实现的键值对存储结构,它继承自 AbstractMap 类并实现了 Map 接口。HashMap 允许使用 null 作为键和值,并且不保证元素的顺序。下面详细介绍 HashMap 的特性、用法及内部原理。

HashMap 的核心特性

无序性:元素的存储顺序与插入顺序无关。
唯一性:键不能重复,若插入相同的键,新值会覆盖旧值。
允许 null:键和值均可为 null,但键的 null 只能有一个。
非线程安全:适用于单线程环境;多线程环境下建议使用 ConcurrentHashMap。
高效性:基于哈希表,基本操作(put、get)的时间复杂度为 O(1)。

HashMap 的常用方法

以下是 HashMap 的核心方法示例:

import java.util.HashMap;
import java.util.Map;

public class HashMapExample {
    public static void main(String[] args) {
        // 创建 HashMap
        Map<String, Integer> scores = new HashMap<>();

        // 添加元素
        scores.put("Alice", 90);
        scores.put("Bob", 85);
        scores.put("Charlie", 95);
        scores.put(null, 100); // 允许 null 键
        scores.put("David", null); // 允许 null 值

        // 获取元素
        System.out.println("Alice 的分数: " + scores.get("Alice")); // 90
        System.out.println("null 键的值: " + scores.get(null)); // 100

        // 检查键/值是否存在
        System.out.println("是否包含 Bob: " + scores.containsKey("Bob")); // true
        System.out.println("是否包含值 95: " + scores.containsValue(95)); // true

        // 删除元素
        scores.remove("Charlie");
        System.out.println("删除 Charlie 后: " + scores);

        // 遍历方式一:使用 entrySet
        System.out.println("遍历方式一(entrySet):");
        for (Map.Entry<String, Integer> entry : scores.entrySet()) {
            System.out.println(entry.getKey() + ": " + entry.getValue());
        }

        // 遍历方式二:使用 keySet
        System.out.println("遍历方式二(keySet):");
        for (String key : scores.keySet()) {
            System.out.println(key + ": " + scores.get(key));
        }

        // 遍历方式三:使用 forEach + Lambda
        System.out.println("遍历方式三(forEach + Lambda):");
        scores.forEach((key, value) -> System.out.println(key + ": " + value));

        // 获取大小
        System.out.println("HashMap 大小: " + scores.size()); // 4
    }
}

HashMap 的内部原理

哈希表结构
HashMap 使用数组 + 链表 / 红黑树实现。当发生哈希冲突时,元素会以链表形式存储;当链表长度超过 8 且数组长度超过 64 时,链表会转换为红黑树以提高查询效率。
哈希冲突处理
通过链地址法(Separate Chaining)解决冲突,即多个元素映射到同一位置时,以链表或树结构存储。
扩容机制
初始容量为 16,负载因子(Load Factor)默认为 0.75。
当元素数量超过 容量 × 负载因子 时,会触发扩容(Resize),容量翻倍并重新哈希。

自定义对象作为键的注意事项

若使用自定义对象作为键,必须重写 hashCode() 和 equals() 方法:
hashCode():确保相同对象返回相同哈希值。
equals():定义对象相等的逻辑。

import java.util.HashMap;
import java.util.Objects;

class Student {
    private final String name;
    private final int id;

    public Student(String name, int id) {
        this.name = name;
        this.id = id;
    }

    // 重写 hashCode()
    @Override
    public int hashCode() {
        return Objects.hash(name, id);
    }

    // 重写 equals()
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Student student = (Student) o;
        return id == student.id && name.equals(student.name);
    }

    @Override
    public String toString() {
        return "Student{name='" + name + "', id=" + id + "}";
    }
}

public class CustomKeyExample {
    public static void main(String[] args) {
        HashMap<Student, Integer> studentScores = new HashMap<>();
        studentScores.put(new Student("Alice", 1), 90);
        studentScores.put(new Student("Bob", 2), 85);

        // 通过相同属性的对象获取值(必须重写 hashCode 和 equals)
        System.out.println("Alice 的分数: " + studentScores.get(new Student("Alice", 1))); // 90
    }
}

HashMap vs. Hashtable vs. ConcurrentHashMap

特性 HashMap Hashtable ConcurrentHashMap
线程安全 否 是(全同步) 是(分段锁 / CAS)
null 键 / 值 允许 不允许 不允许
性能 高 低(全同步开销) 高(并发优化)
适用场景 单线程 多线程(已过时) 多线程

常见面试问题

HashMap 的工作原理
基于哈希表,通过 hashCode() 定位桶位置,通过 equals() 比较键。
为什么负载因子是 0.75
权衡空间和时间效率:过小会频繁扩容,过大会增加哈希冲突概率。
HashMap 是否线程安全?如何替代?
不安全,多线程环境下使用 ConcurrentHashMap。
HashMap 在 JDK 8 有哪些优化?
引入红黑树,优化哈希冲突时的性能(链表转树)。
掌握 HashMap 的核心原理和用法是 Java 开发的基础,它广泛应用于缓存、数据统计、配置管理等场景。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

孤独又灿烂的神

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值