发布于2026-06-30 阅读(0)
扫一扫,手机访问
说实话,在学习 Ja va 集合框架时,HashMap 往往是大家最先接触的 Map 实现。但在实际开发里,另外两个“狠角色”——LinkedHashMap 和 TreeMap——同样出场率极高。它们都实现了 Map 接口,但脾性截然不同。
这篇文章会从概念、底层原理、核心差异、适用场景和代码实例这几个维度,帮你把它们彻底吃透。
Map 就是典型的“键值对(key-value)”数据结构,形如 key → value。例如:"张三" → 18,"李四" → 20。
Ja va 中常见的 Map 实现大致分三类:
| 类型 | 特点 |
|---|---|
| HashMap | 无序 |
| LinkedHashMap | 有序 |
| TreeMap | 自动排序 |
LinkedHashMap 是 HashMap 的子类,它的最大特色就在于——能够完美保持元素的插入顺序。
举个例子:往 Map 里依次放入 1 → A、3 → C、2 → B,遍历时拿到的顺序依然是 1、3、2,绝不会像 HashMap 那样打乱顺序。
一句话概括:LinkedHashMap = HashMap + 双向链表。
它内部同时保持了 HashMap 的哈希存储结构,以及一个双向链表来维护元素的顺序。整体结构可以理解为:数组 + 链表 + 红黑树 + 双向链表。HashMap 负责高效的查询,双向链表则负责“记住”元素进来的先后顺序。
| 特点 | 说明 |
|---|---|
| 有序 | 按插入顺序排列 |
| 查询快 | 基于 HashMap |
| 允许 null | key 和 value 都允许 |
| 非线程安全 | 多线程需额外处理 |
import ja va.util.LinkedHashMap;
public class Demo {
public static void main(String[] args) {
LinkedHashMap map = new LinkedHashMap<>();
map.put(3, "Ja va");
map.put(1, "Python");
map.put(2, "C++");
System.out.println(map);
}
}
输出:
{3=Ja va, 1=Python, 2=C++}
可以看到,顺序与插入顺序完全一致。
import ja va.util.LinkedHashMap;
import ja va.util.Map;
public class Demo {
public static void main(String[] args) {
LinkedHashMap map = new LinkedHashMap<>();
map.put(1, "张三");
map.put(2, "李四");
map.put(3, "王五");
for (Map.Entry entry : map.entrySet()) {
System.out.println(
entry.getKey() + " : " + entry.getValue()
);
}
}
}
输出:
1 : 张三
2 : 李四
3 : 王五
LinkedHashMap 支持两种顺序模式:
| 顺序 | 说明 |
|---|---|
| 插入顺序 | 默认 |
| 访问顺序 | 最近访问的排后面 |
开启访问顺序模式也很简单:
new LinkedHashMap<>(16, 0.75f, true)
第三个参数传 true 就表示开启访问顺序。
import ja va.util.LinkedHashMap;
import ja va.util.Map;
public class Demo {
public static void main(String[] args) {
LinkedHashMap map =
new LinkedHashMap<>(16, 0.75f, true);
map.put(1, "A");
map.put(2, "B");
map.put(3, "C");
//访问元素
map.get(1);
System.out.println(map);
}
}
输出:
{2=B, 3=C, 1=A}
因为 1 被访问后移动到了末尾,这正是很多缓存系统的核心策略——LRU(最近最少使用)。
TreeMap 最大的特点:自动排序。无论你插入的顺序如何,它都会按照 key 来自动排序。
TreeMap 底层基于红黑树(Red-Black Tree)实现。红黑树是一种自平衡的二叉搜索树,核心特性很突出:查询效率高、自动排序、增删改效率稳定。
时间复杂度方面:
| 操作 | 时间复杂度 |
|---|---|
| put | O(log n) |
| get | O(log n) |
| remove | O(log n) |
| 特点 | 说明 |
|---|---|
| 自动排序 | 按 key 排序 |
| 不允许 key 为 null | 会报空指针异常 |
| 查询效率稳定 | 红黑树实现 |
| 非线程安全 | 多线程需同步 |
默认情况下,TreeMap 会按照 key 的自然顺序进行排序。
import ja va.util.TreeMap;
public class Demo {
public static void main(String[] args) {
TreeMap map = new TreeMap<>();
map.put(3, "Ja va");
map.put(1, "Python");
map.put(2, "C++");
System.out.println(map);
}
}
输出:
{1=Python, 2=C++, 3=Ja va}
即使插入顺序是 3、1、2,输出结果仍然是自动排序后的结果。
import ja va.util.TreeMap;
public class Demo {
public static void main(String[] args) {
TreeMap map = new TreeMap<>();
map.put("banana", 1);
map.put("apple", 2);
map.put("cat", 3);
System.out.println(map);
}
}
输出:
{apple=2, banana=1, cat=3}
字符串会按字母顺序进行排序。
如果想让 TreeMap 按自己的规则排序,可以使用Comparator 比较器来实现。
import ja va.util.Comparator;
import ja va.util.TreeMap;
public class Demo {
public static void main(String[] args) {
TreeMap map =
new TreeMap<>(Comparator.reverseOrder());
map.put(1, "A");
map.put(3, "C");
map.put(2, "B");
System.out.println(map);
}
}
输出:
{3=C, 2=B, 1=A}
如果 key 是自定义对象,那么该对象必须实现 Comparable 接口,或者在构造 TreeMap 时传入一个 Comparator,否则运行时就会报错。
class Student {
String name;
int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return name + "-" + age;
}
}
import ja va.util.Comparator;
import ja va.util.TreeMap;
public class Demo {
public static void main(String[] args) {
TreeMap map =
new TreeMap<>((o1, o2) -> o1.age - o2.age);
map.put(new Student("张三", 18), "Ja va");
map.put(new Student("李四", 20), "Python");
map.put(new Student("王五", 19), "C++");
System.out.println(map);
}
}
输出:
{张三-18=Ja va, 王五-19=C++, 李四-20=Python}
| 对比项 | LinkedHashMap | TreeMap |
|---|---|---|
| 是否有序 | 按插入顺序 | 自动排序 |
| 底层结构 | Hash表 + 双向链表 | 红黑树 |
| 查询效率 | O(1) | O(log n) |
| 是否允许 null key | 允许 | 不允许 |
| 使用场景 | 记录顺序 | 排序需求 |
例如:最近播放歌曲、最近浏览商品等场景。
例如:学生成绩排名、商品价格排序等场景。
LinkedHashMap 是有序的,内部多了一个双向链表;而 HashMap 是无序的,纯哈希结构。
因为底层是红黑树,插入元素时会自动比较 key,从而实现排序。
因为排序时需要调用 compareTo() 方法来比较 key,而 null 无法被比较,会直接抛出空指针异常。
因为它支持访问顺序这种模式:最近访问的数据会自动移动到链表尾部。这正好符合 LRU(最近最少使用)缓存淘汰策略。
核心关键词:有序、插入顺序、双向链表、缓存。适合那种既想要 HashMap 的高效查询,又需要保持元素顺序的场景。
核心关键词:自动排序、红黑树、比较器、有序Map。适合那些需要按 key 自动排序的场景。
Map
├── HashMap
│ ├── 无序
│ └── 查询快
│
├── LinkedHashMap
│ ├── 有序
│ ├── 双向链表
│ └── 适合缓存
│
└── TreeMap
├── 自动排序
├── 红黑树
└── 适合排行榜
真正掌握集合框架后,其实我们会发现:Ja va 集合本质就是“数据结构 + 算法思想”的具体实现。
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
正版软件
正版软件
正版软件
正版软件
正版软件
1
2
3
7
8