跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客我的书AI学习GitHub 精选镜像AI 生图工具UI配色美学关于
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
Javajava算法

Java 集合框架进阶:Map 接口核心原理与实战

Java Map 接口是键值对集合,Key 唯一 Value 可重复。HashMap 基于哈希表,JDK8 采用数组加链表红黑树结构,解决哈希冲突并优化查询效率。LinkedHashMap 维护插入或访问顺序,常用于实现 LRU 缓存。TreeMap 基于红黑树自动排序 Key。Hashtable 线程安全但性能低,ConcurrentHashMap 通过 CAS 和分段锁实现高并发安全。自定义对象作 Key 需重写 hashCode 和 equals 方法。

黑客发布于 2026/3/23更新于 2026/10/2091 浏览
Java 集合框架进阶:Map 接口核心原理与实战

Java 集合框架进阶:Map 接口核心原理与实战

在这里插入图片描述

1.1 本章学习目标与重点

💡 掌握 Map 接口的核心特性,理解 Key-Value 键值对的存储结构与设计思想。 💡 熟练掌握 HashMap、LinkedHashMap、TreeMap 等实现类的底层原理与适用场景。 💡 理解 Map 集合的线程安全问题,掌握并发环境下的解决方案。 ⚠️ 本章重点是 HashMap 的底层实现原理 和 不同 Map 实现类的性能对比,这是面试和开发中的高频核心考点。

1.2 Map 接口核心概述

1.2.1 Map 接口的定义与特性

💡 Map 是一种键值对(Key-Value) 集合,它的核心是通过键(Key)来唯一标识值(Value)。 Map 接口中的 Key 具有唯一性,不能重复;Value 可以重复,并且可以为 null。 Map 接口与 Collection 接口是并列关系,它不属于 Collection 体系,没有继承关系。

Map 接口的核心方法:

  • put(K key, V value):添加键值对,Key 重复时会覆盖原有 Value
  • get(Object key):根据 Key 获取 Value,Key 不存在时返回 null
  • remove(Object key):根据 Key 删除对应的键值对
  • containsKey(Object key):判断是否包含指定 Key
  • containsValue(Object value):判断是否包含指定 Value
  • keySet():获取所有 Key 组成的 Set 集合
  • values():获取所有 Value 组成的 Collection 集合
  • entrySet():获取所有键值对(Map.Entry)组成的 Set 集合

✅ 核心结论:Map 适合通过唯一标识(Key)快速查找对应数据(Value)的场景。

1.2.2 Map 集合的遍历方式

Map 集合有三种常用的遍历方式,我们以 HashMap 为例进行代码实操:

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

public class MapTraversalDemo {
    public static void main(String[] args) {
        Map<String, String> map = new HashMap<>();
        map.put("name", "张三");
        map.put("age", "20");
        map.put("gender", "男");

        // 方式 1:遍历所有 Key,通过 Key 获取 Value
        System.out.println("方式 1:遍历 Key 获取 Value");
        Set<String> keySet = map.keySet();
        for (String key : keySet) {
            String value = map.get(key);
            System.out.println(key + "=" + value);
        }

        // 方式 2:遍历所有键值对(Map.Entry)
        System.out.println("\n方式 2:遍历 Map.Entry");
        Set<Map.Entry<String, String>> entrySet = map.entrySet();
        for (Map.Entry<String, String> entry : entrySet) {
            System.out.println(entry.getKey() + "=" + entry.getValue());
        }

        // 方式 3:JDK8+ Lambda 表达式遍历
        System.out.println("\n方式 3:Lambda 表达式遍历");
        map.forEach((key, value) -> System.out.println(key + "=" + value));
    }
}

输出结果

方式 1:遍历 Key 获取 Value name=张三 age=20 gender=男 
方式 2:遍历 Map.Entry name=张三 age=20 gender=男 
方式 3:Lambda 表达式遍历 name=张三 age=20 gender=男 

✅ 核心结论:遍历大量数据时,方式 2(entrySet)效率最高,因为它避免了通过 Key 重复查询 Value 的操作。

1.3 HashMap:基于哈希表的实现

1.3.1 HashMap 底层原理(JDK8)

💡 JDK8 中 HashMap 的底层结构是 数组 + 链表 + 红黑树 的组合结构,目的是解决哈希冲突,提升查询效率。

  1. 数组(哈希桶):数组的每个元素是一个链表或红黑树的头节点,默认初始容量为 16,默认加载因子为 0.75。
  2. 链表:当多个 Key 的哈希值相同,且对应数组下标位置已有元素时,会以链表形式存储,称为哈希冲突。
  3. 红黑树:当链表长度超过阈值(默认为 8),并且数组长度大于等于 64 时,链表会转换为红黑树,将查询时间复杂度从 O(n) 降低到 O(log n)。

HashMap 的核心存储流程: ① 📝 计算 Key 的哈希值:通过 hash(key) 方法计算,目的是降低哈希冲突概率。 ② 📝 计算数组下标:(数组长度 - 1) & 哈希值,等价于取模运算但效率更高。 ③ 📝 判断下标位置是否为空:为空则直接插入新节点;不为空则判断 Key 是否重复。 ④ 📝 处理 Key 重复:Key 重复则覆盖 Value;不重复则插入链表或红黑树。 ⑤ 📝 扩容判断:当元素个数超过 数组容量 * 加载因子 时,数组会扩容为原来的 2 倍。

1.3.2 代码实操:HashMap 的常用操作
import java.util.HashMap;
import java.util.Map;

public class HashMapDemo {
    public static void main(String[] args) {
        Map<String, Integer> hashMap = new HashMap<>();

        // 1. 添加键值对
        hashMap.put("语文", 90);
        hashMap.put("数学", 95);
        hashMap.put("英语", 92);
        hashMap.put("数学", 100); // Key 重复,覆盖原有 Value

        System.out.println("HashMap 内容:" + hashMap);

        // 2. 根据 Key 获取 Value
        Integer mathScore = hashMap.get("数学");
        System.out.println("数学成绩:" + mathScore);

        // 3. 判断是否包含指定 Key 或 Value
        boolean hasEnglish = hashMap.containsKey("英语");
        boolean has90 = hashMap.containsValue(90);
        System.out.println("包含英语 Key:" + hasEnglish);
        System.out.println("包含 90 分 Value:" + has90);

        // 4. 删除键值对
        hashMap.remove("语文");
        System.out.println("删除语文后的 HashMap:" + hashMap);

        // 5. 获取集合大小
        int size = hashMap.size();
        System.out.println("HashMap 大小:" + size);

        // 6. 清空集合
        hashMap.clear();
        System.out.println("清空后是否为空:" + hashMap.isEmpty());
    }
}

输出结果

HashMap 内容:{语文=90, 数学=100, 英语=92} 
数学成绩:100 
包含英语 Key:true 
包含 90 分 Value:true 
删除语文后的 HashMap:{数学=100, 英语=92} 
HashMap 大小:2 
清空后是否为空:true 
1.3.3 自定义对象作为 Key 的注意事项

⚠️ 当使用自定义对象作为 HashMap 的 Key 时,必须重写 hashCode() 和 equals() 方法,否则无法保证 Key 的唯一性。

我们以 Student 类为例,实现基于学号的 Key 唯一性:

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

class Student {
    private String id;
    private String name;

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

    // 重写 equals 方法:根据学号判断 Key 是否相同
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Student student = (Student) o;
        return Objects.equals(id, student.id);
    }

    // 重写 hashCode 方法:根据学号计算哈希值
    @Override
    public int hashCode() {
        return Objects.hash(id);
    }

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

public class HashMapCustomKeyDemo {
    public static void main(String[] args) {
        Map<Student, String> studentMap = new HashMap<>();
        Student s1 = new Student("001", "张三");
        Student s2 = new Student("002", "李四");
        Student s3 = new Student("001", "张三"); // 与 s1 学号相同

        studentMap.put(s1, "一班");
        studentMap.put(s2, "二班");
        studentMap.put(s3, "三班"); // Key 重复,覆盖 s1 的 Value

        // 遍历输出
        studentMap.forEach((key, value) -> System.out.println(key + "=" + value));
    }
}

输出结果

Student{id='001', name='张三'}=三班 
Student{id='002', name='李四'}=二班 
1.3.4 HashMap 性能分析
  • 增删查操作:理想情况下时间复杂度为 O(1),哈希冲突严重时会退化为 O(n),红黑树转换后为 O(log n)。
  • 扩容机制:扩容时需要重新计算所有元素的下标,非常消耗性能,开发中建议提前指定初始容量,减少扩容次数。
  • ⚠️ 注意事项:HashMap 是线程不安全的集合,多线程环境下使用会出现数据错乱或 ConcurrentModificationException 异常。

1.4 LinkedHashMap:有序的哈希表

1.4.1 LinkedHashMap 底层原理

💡 LinkedHashMap 是 HashMap 的子类,底层结构是 HashMap + 双向链表。 它通过双向链表维护键值对的插入顺序或访问顺序,保证遍历顺序与插入顺序一致,或者与最近访问顺序一致。 LinkedHashMap 的元素唯一性判断规则与 HashMap 完全相同。

1.4.2 代码实操 1:插入顺序模式(默认)
import java.util.LinkedHashMap;
import java.util.Map;

public class LinkedHashMapInsertOrderDemo {
    public static void main(String[] args) {
        Map<String, String> linkedHashMap = new LinkedHashMap<>();
        linkedHashMap.put("b", "B");
        linkedHashMap.put("a", "A");
        linkedHashMap.put("c", "C");

        // 遍历顺序与插入顺序一致
        linkedHashMap.forEach((key, value) -> System.out.println(key + "=" + value));
    }
}

输出结果

b=B a=A c=C 
1.4.3 代码实操 2:访问顺序模式

通过构造方法 LinkedHashMap(int initialCapacity, float loadFactor, boolean accessOrder) 可以开启访问顺序模式,最近访问的元素会被移到链表尾部。

import java.util.LinkedHashMap;
import java.util.Map;

public class LinkedHashMapAccessOrderDemo {
    public static void main(String[] args) {
        // 开启访问顺序模式:accessOrder = true
        Map<String, String> linkedHashMap = new LinkedHashMap<>(16, 0.75f, true);
        linkedHashMap.put("a", "A");
        linkedHashMap.put("b", "B");
        linkedHashMap.put("c", "C");

        System.out.println("初始顺序:");
        linkedHashMap.forEach((key, value) -> System.out.println(key + "=" + value));

        // 访问元素 a,触发访问顺序调整
        linkedHashMap.get("a");

        System.out.println("\n访问元素 a 后的顺序:");
        linkedHashMap.forEach((key, value) -> System.out.println(key + "=" + value));
    }
}

输出结果

初始顺序: a=A b=B c=C 
访问元素 a 后的顺序: b=B c=C a=A 

✅ 核心结论:访问顺序模式的 LinkedHashMap 可以用来实现 LRU 缓存淘汰算法(最近最少使用淘汰)。

1.4.4 性能分析
  • LinkedHashMap 的增删查效率略低于 HashMap,因为需要维护双向链表的节点引用。
  • 适合需要有序遍历且高效查找的场景,例如缓存系统、配置参数存储等。
  • ⚠️ 注意事项:LinkedHashMap 同样是线程不安全的集合。

1.5 TreeMap:基于红黑树的排序映射

1.5.1 TreeMap 底层原理

💡 TreeMap 的底层结构是红黑树,它会自动对 Key 进行排序,默认是升序排列。 TreeMap 不允许 Key 为 null,因为排序时会抛出空指针异常。 TreeMap 保证 Key 唯一性的方式是通过比较 Key 的大小,而不是 hashCode() 和 equals() 方法。

TreeMap 的两种排序方式:

  1. 自然排序:Key 实现 Comparable 接口,重写 compareTo() 方法。
  2. 定制排序:创建 TreeMap 时传入 Comparator 比较器,自定义排序规则。
1.5.2 代码实操 1:自然排序
import java.util.Map;
import java.util.TreeMap;

public class TreeMapNaturalSortDemo {
    public static void main(String[] args) {
        Map<Integer, String> treeMap = new TreeMap<>();
        treeMap.put(3, "C");
        treeMap.put(1, "A");
        treeMap.put(2, "B");

        // 自动按 Key 升序排列
        treeMap.forEach((key, value) -> System.out.println(key + "=" + value));
    }
}

输出结果

1=A 2=B 3=C 
1.5.3 代码实操 2:定制排序

我们对字符串 Key 进行降序排列,通过 Comparator 实现定制排序:

import java.util.Comparator;
import java.util.Map;
import java.util.TreeMap;

public class TreeMapCustomSortDemo {
    public static void main(String[] args) {
        // 传入比较器,实现 Key 降序排列
        Map<String, Integer> treeMap = new TreeMap<>(new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                return o2.compareTo(o1); // 降序排列
            }
        });
        treeMap.put("Java", 10);
        treeMap.put("Python", 8);
        treeMap.put("Go", 9);
        treeMap.forEach((key, value) -> System.out.println(key + "=" + value));
    }
}

输出结果

Python=8 Java=10 Go=9 
1.5.4 性能分析
  • 增删查操作:时间复杂度稳定为 O(log n),效率低于 HashMap,但支持有序遍历。
  • 适合需要排序和范围查询的场景,例如排行榜、字典排序等。
  • ⚠️ 注意事项:
    1. TreeMap 是线程不安全的集合。
    2. 存储自定义对象作为 Key 时,必须指定排序规则,否则会抛出 ClassCastException。

1.6 Hashtable:线程安全的哈希表

1.6.1 Hashtable 核心特性

💡 Hashtable 是 Map 接口的早期实现类,底层结构是 数组 + 链表(JDK8 没有红黑树优化)。 它的所有方法都添加了 synchronized 关键字,是线程安全的集合。 Hashtable 不允许 Key 或 Value 为 null,默认初始容量为 11,加载因子为 0.75。

1.6.2 性能分析
  • Hashtable 的线程安全是通过方法加锁实现的,锁粒度大,并发性能低。
  • 现代开发中,不推荐使用 Hashtable,优先使用 ConcurrentHashMap 实现线程安全。

1.7 ConcurrentHashMap:并发安全的哈希表

1.7.1 ConcurrentHashMap 核心特性

💡 ConcurrentHashMap 是 JUC 包下的线程安全集合,专门用于解决 HashMap 的并发问题。 JDK8 中 ConcurrentHashMap 的底层结构是 数组 + 链表 + 红黑树,与 HashMap 类似。 它采用分段锁或 CAS + synchronized 的方式实现线程安全,锁粒度小,并发性能远高于 Hashtable。 ConcurrentHashMap 支持 Key 和 Value 为 null(与 Hashtable 不同)。

1.7.2 代码实操:ConcurrentHashMap 的使用
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class ConcurrentHashMapDemo {
    public static void main(String[] args) {
        Map<String, Integer> concurrentMap = new ConcurrentHashMap<>();

        // 多线程环境下安全操作
        new Thread(() -> {
            for (int i = 0; i < 1000; i++) {
                concurrentMap.put("thread1_" + i, i);
            }
        }).start();
        new Thread(() -> {
            for (int i = 0; i < 1000; i++) {
                concurrentMap.put("thread2_" + i, i);
            }
        }).start();

        // 等待线程执行完成
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("ConcurrentHashMap 大小:" + concurrentMap.size());
    }
}

输出结果

ConcurrentHashMap 大小:2000 

✅ 核心结论:多线程环境下优先使用 ConcurrentHashMap,兼顾线程安全和并发性能。

1.8 实战案例:基于 Map 实现 LRU 缓存

1.8.1 需求分析

💡 实现一个 LRU(最近最少使用)缓存工具类,满足以下需求:

  1. 缓存容量有限,超出容量时自动淘汰最近最少使用的元素。
  2. 支持缓存的添加、查询、删除操作。
  3. 保证操作的时间复杂度尽可能低。
1.8.2 实现思路

利用 LinkedHashMap 的访问顺序模式实现 LRU 缓存,重写 removeEldestEntry() 方法,自定义淘汰规则。

1.8.3 代码实现
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * 基于 LinkedHashMap 实现的 LRU 缓存
 */
public class LRUCache<K, V> extends LinkedHashMap<K, V> {
    // 缓存最大容量
    private final int maxCapacity;

    // 构造方法:开启访问顺序模式
    public LRUCache(int maxCapacity) {
        super(16, 0.75f, true);
        this.maxCapacity = maxCapacity;
    }

    /**
     * 重写该方法,自定义淘汰规则
     * @param eldest 最久未使用的元素
     * @return true 表示淘汰该元素,false 表示不淘汰
     */
    @Override
    protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
        // 当元素个数超过最大容量时,淘汰最久未使用的元素
        return size() > maxCapacity;
    }

    // 测试方法
    public static void main(String[] args) {
        LRUCache<String, Integer> cache = new LRUCache<>(3);

        // 添加缓存元素
        cache.put("A", 1);
        cache.put("B", 2);
        cache.put("C", 3);
        System.out.println("初始缓存:" + cache);

        // 访问元素 A,调整访问顺序
        cache.get("A");
        System.out.println("访问 A 后的缓存:" + cache);

        // 添加元素 D,超出容量,淘汰最久未使用的 B
        cache.put("D", 4);
        System.out.println("添加 D 后的缓存:" + cache);
    }
}

输出结果

初始缓存:{A=1, B=2, C=3} 
访问 A 后的缓存:{B=2, C=3, A=1} 
添加 D 后的缓存:{C=3, A=1, D=4} 
1.8.4 案例总结

✅ 这个 LRU 缓存工具类充分利用了 LinkedHashMap 的特性,代码简洁且性能高效。 通过重写 removeEldestEntry() 方法,轻松实现了缓存淘汰规则,在实际开发中可直接用于本地缓存场景。

1.9 本章总结

  1. Map 是键值对集合,Key 唯一,Value 可重复,常用实现类有 HashMap、LinkedHashMap、TreeMap。
  2. HashMap 底层是数组 + 链表 + 红黑树,查询效率高,适合快速查找场景,线程不安全。
  3. LinkedHashMap 基于 HashMap+ 双向链表,支持插入顺序或访问顺序遍历,可实现 LRU 缓存。
  4. TreeMap 底层是红黑树,支持 Key 排序,适合有序遍历和范围查询场景,线程不安全。
  5. 多线程环境下,优先使用 ConcurrentHashMap 保证线程安全,避免使用 Hashtable。
  6. 自定义对象作为 HashMap Key 时,必须重写 hashCode() 和 equals() 方法。

目录

  1. Java 集合框架进阶:Map 接口核心原理与实战
  2. 1.1 本章学习目标与重点
  3. 1.2 Map 接口核心概述
  4. 1.2.1 Map 接口的定义与特性
  5. 1.2.2 Map 集合的遍历方式
  6. 1.3 HashMap:基于哈希表的实现
  7. 1.3.1 HashMap 底层原理(JDK8)
  8. 1.3.2 代码实操:HashMap 的常用操作
  9. 1.3.3 自定义对象作为 Key 的注意事项
  10. 1.3.4 HashMap 性能分析
  11. 1.4 LinkedHashMap:有序的哈希表
  12. 1.4.1 LinkedHashMap 底层原理
  13. 1.4.2 代码实操 1:插入顺序模式(默认)
  14. 1.4.3 代码实操 2:访问顺序模式
  15. 1.4.4 性能分析
  16. 1.5 TreeMap:基于红黑树的排序映射
  17. 1.5.1 TreeMap 底层原理
  18. 1.5.2 代码实操 1:自然排序
  19. 1.5.3 代码实操 2:定制排序
  20. 1.5.4 性能分析
  21. 1.6 Hashtable:线程安全的哈希表
  22. 1.6.1 Hashtable 核心特性
  23. 1.6.2 性能分析
  24. 1.7 ConcurrentHashMap:并发安全的哈希表
  25. 1.7.1 ConcurrentHashMap 核心特性
  26. 1.7.2 代码实操:ConcurrentHashMap 的使用
  27. 1.8 实战案例:基于 Map 实现 LRU 缓存
  28. 1.8.1 需求分析
  29. 1.8.2 实现思路
  30. 1.8.3 代码实现
  31. 1.8.4 案例总结
  32. 1.9 本章总结

更多推荐文章

查看全部
  • TTS 接口加密逆向分析:基于 WebAssembly 的请求响应全流程
  • Linux 系统权限详解:用户、文件与目录管理
  • 2026 年前端、后端及算法岗位 AI 技能清单
  • 基于 C++ 的第三方 SDK 封装实践:ASR 与短信服务
  • 8 个高效 Python 数据分析技巧
  • 在 AutoDL 上用 LLaMA-Factory 微调 GPT-OSS-20B
  • C++ 图论实战:深入理解三种最短路径算法
  • 轻小说机翻机器人:架构设计与快速部署
  • Python 核心语法详解:变量、流程控制与函数实战
  • 文心一言 4.5 开源模型部署实战与多场景应用解析
  • 生物信息学入门核心技能:Linux、R 与 Python
  • Python 极简教程:Java 开发者视角入门实战
  • LLaMA Factory 核心原理讲解
  • SD-Trainer 快速上手:AI 绘画模型训练实战
  • N46Whisper 基于 Google Colab 的日语语音转字幕工具
  • C++ 实验:cout 与 printf 输出速度对比
  • 数据结构:KMP 算法、Trie 树与并查集详解
  • Python Web 日志管理:从监控到问题定位的实战指南
  • Flutter Web 混合开发:构建跨平台 Web 应用
  • 算法模拟专题:LeetCode 精选例题解析

相关免费在线工具

  • Keycode 信息

    查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online

  • Escape 与 Native 编解码

    JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online

  • JavaScript / HTML 格式化

    使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online

  • JavaScript 压缩与混淆

    Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online

  • 加密/解密文本

    使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online

  • Gemini 图片去水印

    基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online