文章目录
-
- 前言
- 一、为什么需要集合框架
-
- [1.1 数组的局限](#1.1 数组的局限)
- [1.2 集合框架解决了什么问题](#1.2 集合框架解决了什么问题)
- [二、Java 集合框架的整体结构](#二、Java 集合框架的整体结构)
-
- [2.1 两条核心支线](#2.1 两条核心支线)
- [2.2 接口与实现类](#2.2 接口与实现类)
- 三、List:有序、可重复的列表
-
- [3.1 List 的特点](#3.1 List 的特点)
- [3.2 ArrayList:动态数组](#3.2 ArrayList:动态数组)
- [3.3 LinkedList:双向链表](#3.3 LinkedList:双向链表)
- 四、Set:元素不能重复的集合
-
- [4.1 Set 的特点](#4.1 Set 的特点)
- [4.2 HashSet:快速去重](#4.2 HashSet:快速去重)
- [4.3 LinkedHashSet:去重并保留原顺序](#4.3 LinkedHashSet:去重并保留原顺序)
- [4.4 TreeSet:去重并排序](#4.4 TreeSet:去重并排序)
- [五、Queue 与 Deque:等待处理的数据队列](#五、Queue 与 Deque:等待处理的数据队列)
- 六、Map:通过键查找值
-
- [6.1 Map 的特点](#6.1 Map 的特点)
- [6.2 HashMap:最常用的键值容器](#6.2 HashMap:最常用的键值容器)
- [6.3 LinkedHashMap:按插入顺序遍历](#6.3 LinkedHashMap:按插入顺序遍历)
- [6.4 TreeMap:按照键排序](#6.4 TreeMap:按照键排序)
- 七、常用集合如何选择
-
- [7.1 选型思路](#7.1 选型思路)
- [7.2 最常见的默认选择](#7.2 最常见的默认选择)
- 八、测试代码
- 九、常见易混知识点
-
- [9.1 Collection 与 Collections 不一样](#9.1 Collection 与 Collections 不一样)
- [9.2 Map 不属于 Collection 子接口](#9.2 Map 不属于 Collection 子接口)
- 总结
前言
在程序开发中,我们经常需要保存和处理一组数据,例如购物车中的商品、文章标签、排队等待执行的任务、学生姓名与成绩的对应关系。
数组虽然也能保存多个元素,但它的长度固定,增删元素不够灵活。Java 集合框架就像一套准备好的"数据收纳工具箱":不同的容器有不同的摆放规则,也适用于不同的业务场景。
Java 集合框架主要分为两条路线:
Collection:保存一个个独立元素,下面包括List、Set、Queue。Map:保存键值对,例如"用户名 → 用户信息"。
需要特别注意:Map 属于集合框架的一部分,但它不是 Collection 的子接口。
一、为什么需要集合框架
1.1 数组的局限
数组适合保存数量比较固定的数据:
java
String[] names = new String[3];
names[0] = "张三";
names[1] = "李四";
names[2] = "王五";
但是,当数据数量不断变化时,数组会显得不够灵活:
- 数组长度创建后不能自动改变。
- 中间插入或删除元素比较麻烦。
- 查找、去重、排序等操作通常需要自己编写代码。
例如,一个购物车可能随时添加或删除商品;一个班级的签到名单也可能不断变化。这时,集合比数组更适合。
1.2 集合框架解决了什么问题
Java 集合框架提供了统一的接口和常用实现类,使我们可以直接完成以下操作:
java
list.add("Java");
list.remove("MySQL");
set.contains("Redis");
map.get("张三");
queue.poll();
可以把集合框架理解为不同用途的容器:
| 容器 | 形象理解 | 典型用途 |
|---|---|---|
List |
可重复的排号座位表 | 购物车、学生名单 |
Set |
不允许重复入场的名单 | 标签去重、用户名检测 |
Queue |
排队窗口 | 打印任务、消息处理 |
Deque |
两头都能进出的通道 | 栈、撤销操作 |
Map |
按编号查资料的柜子 | 用户 ID 查询、配置表 |
二、Java 集合框架的整体结构
2.1 两条核心支线
Java 集合框架的基础结构可以简化为:
text
Iterable
|
Collection
├── List
│ ├── ArrayList
│ └── LinkedList
│
├── Set
│ ├── HashSet
│ ├── LinkedHashSet
│ └── TreeSet
│
└── Queue
├── PriorityQueue
└── Deque
├── ArrayDeque
└── LinkedList
Map
├── HashMap
├── LinkedHashMap
└── TreeMap
其中:
List关注元素的排列位置。Set关注元素不能重复。Queue关注元素按照某种规则依次处理。Map关注通过唯一的键查找对应的值。(二哥的Java进阶之路)
2.2 接口与实现类
实际开发中,通常使用接口声明变量,再选择具体实现类创建对象:
java
List<String> list = new ArrayList<>();
Set<String> set = new HashSet<>();
Queue<String> queue = new ArrayDeque<>();
Map<String, Integer> map = new HashMap<>();
这种写法可以理解为:
- 左边决定"我需要什么功能"
- 右边决定"底层使用什么结构实现"
例如:
java
List<String> list = new ArrayList<>();
表示当前业务需要的是"列表"功能,至于底层先使用动态数组实现。以后需要更换实现类时,业务代码受到的影响会更小。
三、List:有序、可重复的列表
3.1 List 的特点
List 表示一个有顺序的集合,元素可以重复,并且可以通过下标访问。
java
List<String> courses = new ArrayList<>();
courses.add("Java");
courses.add("MySQL");
courses.add("Java");
System.out.println(courses); // [Java, MySQL, Java]
System.out.println(courses.get(1)); // MySQL
这里第二次添加 "Java" 不会被拦截,因为 List 允许重复元素。
适用场景:
- 购物车商品列表。
- 用户浏览记录。
- 按顺序展示的文章评论。
- 考试成绩列表。
List 官方定义强调了两个核心能力:元素具有顺序,并且可以按整数下标访问;它通常允许重复元素。(Oracle Docs)
3.2 ArrayList:动态数组
ArrayList 底层可以理解为一个能够自动扩容的数组。
java
List<String> cart = new ArrayList<>();
cart.add("键盘");
cart.add("鼠标");
cart.add("显示器");
System.out.println(cart.get(1)); // 鼠标
它的特点如下:
| 操作 | 特点 |
|---|---|
| 按下标查询 | 快,适合频繁读取 |
| 尾部添加元素 | 通常较快 |
| 中间插入或删除 | 需要移动后面的元素 |
| 内存结构 | 元素连续存放,额外开销较少 |
可以把 ArrayList 想象成一排电影院座位。找到第 10 个座位很快,但如果要在中间增加一个座位,后面的人可能都要往后移动。
适用场景:
- 查询操作多的列表。
- 商品展示列表。
- 查询结果集合。
- 一般业务中的默认
List实现。
ArrayList 是 List 的可调整大小数组实现,并实现了随机访问能力。(Oracle Docs)
3.3 LinkedList:双向链表
LinkedList 底层由一个个相互连接的节点组成,每个节点知道前一个节点和后一个节点。
java
List<String> history = new LinkedList<>();
history.add("首页");
history.add("课程页");
history.add("订单页");
System.out.println(history);
它的特点如下:
| 操作 | 特点 |
|---|---|
| 按下标查询 | 需要沿节点寻找,效率较低 |
| 首尾添加、删除 | 比较适合 |
| 中间插入、删除 | 找到位置后修改连接关系较方便 |
| 内存结构 | 每个节点需要保存前后引用 |
可以把 LinkedList 想象成一列手拉手的小火车。增加或移除一节车厢时,只需要调整相邻连接;但要直接找到第 100 节车厢,就需要一路数过去。
需要注意:不能简单理解为"LinkedList 任意位置增删都一定快"。如果需要先通过下标找到中间位置,寻找节点本身仍然需要遍历。
LinkedList 同时实现了 List 和 Deque,按下标访问时会从头部或尾部开始遍历。(Oracle Docs)
四、Set:元素不能重复的集合
4.1 Set 的特点
Set 的核心特点是:不允许保存重复元素。
java
Set<String> tags = new HashSet<>();
tags.add("Java");
tags.add("MySQL");
tags.add("Java");
System.out.println(tags.size()); // 2
第二次添加 "Java" 时,集合不会重复保存它。
适用场景:
- 对文章标签去重。
- 判断用户名是否已经存在。
- 统计不重复的访问用户。
- 保存不能重复的编号。
需要特别注意:
Set的核心定义是"不重复",而不是"所有实现类都无序"。
不同实现类对顺序的处理方式不同:
| 实现类 | 是否去重 | 顺序特点 |
|---|---|---|
HashSet |
是 | 不保证遍历顺序 |
LinkedHashSet |
是 | 保留插入顺序 |
TreeSet |
是 | 按自然顺序或比较器排序 |
Set 接口规定元素不能重复;HashSet 不保证遍历顺序,而 LinkedHashSet 与 TreeSet 分别提供插入顺序和排序能力。(Oracle Docs)
4.2 HashSet:快速去重
HashSet 底层基于 HashMap 实现,适合快速判断某个元素是否存在。
java
Set<String> uniqueTags = new HashSet<>();
uniqueTags.add("Java");
uniqueTags.add("Redis");
uniqueTags.add("Java");
System.out.println(uniqueTags.contains("Redis")); // true
System.out.println(uniqueTags.size()); // 2
适用场景:
- 单词去重。
- 用户 ID 去重。
- 快速判断数据是否已经处理过。
java
List<String> words = Arrays.asList("Java", "MySQL", "Java", "Redis");
Set<String> uniqueWords = new HashSet<>(words);
System.out.println(uniqueWords);
当哈希分布良好时,HashSet 的 add、remove、contains 和 size 等基本操作通常具有常数时间性能。(Oracle Docs)
4.3 LinkedHashSet:去重并保留原顺序
如果既想去重,又想保留元素首次出现的顺序,可以使用 LinkedHashSet。
java
Set<String> tags = new LinkedHashSet<>();
tags.add("Java");
tags.add("MySQL");
tags.add("Java");
tags.add("Redis");
System.out.println(tags); // [Java, MySQL, Redis]
适用场景:
- 对用户提交的数据去重,但保持展示顺序。
- 对搜索关键词去重,同时保留原始输入顺序。
4.4 TreeSet:去重并排序
TreeSet 会在去重的同时,对元素进行排序。
java
Set<Integer> scores = new TreeSet<>();
scores.add(90);
scores.add(75);
scores.add(88);
scores.add(75);
System.out.println(scores); // [75, 88, 90]
适用场景:
- 保存不重复且需要排序的分数。
- 保存有序编号。
- 查询某个范围内的数据。
TreeSet 基于 TreeMap,按照元素的自然顺序或指定比较器进行排序,其基础操作具有 O(log n) 的时间成本。(Oracle Docs)
五、Queue 与 Deque:等待处理的数据队列
5.1 Queue:先进先出的排队结构
Queue 表示队列,通常遵循先进先出原则,即先来的元素先处理。
java
Queue<String> printQueue = new ArrayDeque<>();
printQueue.offer("文档A");
printQueue.offer("文档B");
printQueue.offer("文档C");
System.out.println(printQueue.poll()); // 文档A
System.out.println(printQueue.poll()); // 文档B
可以把队列理解为食堂排队:
text
入队:新同学站到队尾
出队:最前面的同学先打饭离开
适用场景:
- 打印任务队列。
- 消息消费队列。
- 请求排队处理。
- 广度优先搜索。
Queue 常用方法有两组:
| 操作 | 失败时抛异常 | 失败时返回特殊值 |
|---|---|---|
| 插入元素 | add(e) |
offer(e) |
| 删除队首 | remove() |
poll() |
| 查看队首 | element() |
peek() |
日常使用中,offer()、poll() 和 peek() 往往更安全,因为队列为空时不会直接抛出异常。Queue 通常采用先进先出规则,但 PriorityQueue 等实现类可以使用不同的出队规则。(Oracle Docs)
5.2 Deque:两端都能操作的队列
Deque 是双端队列,元素可以从头部加入或删除,也可以从尾部加入或删除。
java
Deque<String> deque = new ArrayDeque<>();
deque.addFirst("B");
deque.addFirst("A");
deque.addLast("C");
System.out.println(deque); // [A, B, C]
Deque 既可以模拟普通队列,也可以模拟栈。
作为队列使用
java
Queue<String> queue = new ArrayDeque<>();
queue.offer("任务A");
queue.offer("任务B");
System.out.println(queue.poll()); // 任务A
作为栈使用
java
Deque<String> stack = new ArrayDeque<>();
stack.push("首页");
stack.push("商品页");
stack.push("订单页");
System.out.println(stack.pop()); // 订单页
System.out.println(stack.pop()); // 商品页
适用场景:
- 浏览器返回记录。
- 编辑器撤销功能。
- 深度优先搜索。
- 普通业务队列。
虽然 ArrayDeque 底层使用数组实现,但它不是 List,不能通过 get(0) 这样的下标方式访问元素。官方文档还指出,ArrayDeque 用作栈时通常比 Stack 更快,用作队列时通常比 LinkedList 更快。(Oracle Docs)
5.3 PriorityQueue:优先处理重要任务
普通队列按照先来后到处理任务,而 PriorityQueue 会按照优先级决定谁先出队。
java
Queue<Integer> queue = new PriorityQueue<>();
queue.offer(80);
queue.offer(100);
queue.offer(60);
System.out.println(queue.poll()); // 60
默认情况下,数字越小,越先出队。
如果希望"优先级数字越大,任务越重要",可以提供比较器:
java
Queue<Integer> queue = new PriorityQueue<>(Comparator.reverseOrder());
queue.offer(80);
queue.offer(100);
queue.offer(60);
System.out.println(queue.poll()); // 100
适用场景:
- 线上故障优先处理。
- 医院急诊排队。
- 考试成绩排名处理。
- 定时任务调度。
需要注意:PriorityQueue 只保证每次 poll() 取出的元素符合优先级规则,直接遍历整个队列时,不保证输出结果已经完全排好序。(Oracle Docs)
六、Map:通过键查找值
6.1 Map 的特点
Map 保存的是键值对:
text
键 key → 值 value
例如:
text
学号 → 学生姓名
商品编号 → 商品详情
用户名 → 登录信息
配置名称 → 配置值
示例:
java
Map<String, Integer> scores = new HashMap<>();
scores.put("张三", 90);
scores.put("李四", 86);
System.out.println(scores.get("张三")); // 90
Map 中的键不能重复。相同的键再次调用 put() 时,新值会替换旧值:
java
scores.put("张三", 95);
System.out.println(scores.get("张三")); // 95
可以把 Map 理解为快递柜:
text
柜门编号是 key
柜门里面的包裹是 value
同一个柜门编号只能对应一个当前位置上的包裹
Map 的官方定义是键到值的映射,一个键最多只能映射到一个值。(Oracle Docs)
6.2 HashMap:最常用的键值容器
HashMap 是日常开发中非常常见的 Map 实现。
java
Map<String, String> users = new HashMap<>();
users.put("1001", "张三");
users.put("1002", "李四");
System.out.println(users.get("1001")); // 张三
适用场景:
- 用户 ID 查询用户信息。
- 商品编号查询商品详情。
- 单词出现次数统计。
- 缓存临时数据。
java
Map<String, Integer> wordCount = new HashMap<>();
wordCount.put("Java", 1);
wordCount.put("MySQL", 1);
wordCount.put("Java", wordCount.get("Java") + 1);
System.out.println(wordCount.get("Java")); // 2
HashMap 不保证遍历顺序;当哈希分布良好时,其 get() 与 put() 等基本操作通常具有常数时间性能。(Oracle Docs)
6.3 LinkedHashMap:按插入顺序遍历
如果希望键值对按照加入顺序输出,可以使用 LinkedHashMap。
java
Map<String, Integer> steps = new LinkedHashMap<>();
steps.put("登录", 1);
steps.put("选择商品", 2);
steps.put("提交订单", 3);
System.out.println(steps.keySet()); // [登录, 选择商品, 提交订单]
适用场景:
- 需要固定展示顺序的配置项。
- 需要记录访问顺序的数据。
- 需要实现简单 LRU 缓存的场景。
LinkedHashMap 在哈希表基础上维护了链表,因此拥有明确的遍历顺序,默认通常是插入顺序。(Oracle Docs)
6.4 TreeMap:按照键排序
TreeMap 会按照键的自然顺序或比较器规则进行排序。
java
Map<Integer, String> ranking = new TreeMap<>();
ranking.put(3, "铜牌");
ranking.put(1, "金牌");
ranking.put(2, "银牌");
System.out.println(ranking); // {1=金牌, 2=银牌, 3=铜牌}
适用场景:
- 按编号排序的数据。
- 按日期排序的记录。
- 需要范围查询的数据。
TreeMap 基于红黑树实现,其 put()、get()、remove() 和 containsKey() 等操作具有 O(log n) 的时间成本。(Oracle Docs)
七、常用集合如何选择
7.1 选型思路
选择集合时,不要先背实现类,而应该先问业务需要什么能力:
| 业务需求 | 推荐接口 | 常用实现类 |
|---|---|---|
| 数据允许重复,并且需要下标访问 | List |
ArrayList |
| 数据允许重复,经常在首尾操作 | List / Deque |
LinkedList 或 ArrayDeque |
| 数据不能重复,不关心顺序 | Set |
HashSet |
| 数据不能重复,同时保留插入顺序 | Set |
LinkedHashSet |
| 数据不能重复,同时自动排序 | Set |
TreeSet |
| 按先来后到处理任务 | Queue |
ArrayDeque |
| 按优先级处理任务 | Queue |
PriorityQueue |
| 根据唯一键快速查询值 | Map |
HashMap |
| 根据键查询值,并保留插入顺序 | Map |
LinkedHashMap |
| 根据键查询值,并按键排序 | Map |
TreeMap |
7.2 最常见的默认选择
在普通业务开发中,可以先记住以下组合:
java
List<String> list = new ArrayList<>();
Set<String> set = new HashSet<>();
Queue<String> queue = new ArrayDeque<>();
Map<String, String> map = new HashMap<>();
当业务明确提出"需要保持顺序""需要自动排序""需要优先级处理"等要求时,再更换为对应实现类。
八、测试代码
下面的完整代码演示以下内容:
ArrayList的增删改查与重复元素。LinkedList作为普通列表使用。HashSet、LinkedHashSet、TreeSet的区别。ArrayDeque作为队列和栈使用。PriorityQueue按任务优先级出队。HashMap、LinkedHashMap、TreeMap的区别。
代码兼容 JDK 8 及以上版本。
java
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Deque;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.PriorityQueue;
import java.util.Queue;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
/**
* Java 集合框架综合测试:JDK 8+ 可运行。
*/
public class CollectionFrameworkDemo {
public static void main(String[] args) {
testList();
testSet();
testQueueAndDeque();
testPriorityQueue();
testMap();
}
/**
* 测试 List:
* 1. 元素有顺序
* 2. 元素可以重复
* 3. 可以通过下标访问和修改元素
*/
private static void testList() {
System.out.println("===== 1. List:有序、可重复、可按下标访问 =====");
List<String> shoppingCart = new ArrayList<>();
shoppingCart.add("Java书");
shoppingCart.add("键盘");
shoppingCart.add("Java书"); // List 允许重复
shoppingCart.add(1, "鼠标"); // 在指定下标插入
System.out.println("ArrayList 初始内容:" + shoppingCart);
System.out.println("下标为 1 的商品:" + shoppingCart.get(1));
shoppingCart.set(1, "无线鼠标"); // 修改指定下标元素
shoppingCart.remove("键盘"); // 删除指定元素
System.out.println("修改和删除后:" + shoppingCart);
List<String> recentPages = new LinkedList<>();
recentPages.add("首页");
recentPages.add("课程页");
recentPages.add("订单页");
System.out.println("LinkedList 作为普通列表:" + recentPages);
System.out.println();
}
/**
* 测试 Set:
* 1. 自动去重
* 2. 不同实现类具有不同的顺序特点
*/
private static void testSet() {
System.out.println("===== 2. Set:元素不重复,具体实现决定顺序 =====");
List<String> tags = Arrays.asList(
"Java", "MySQL", "Java", "Redis", "MySQL"
);
Set<String> hashSet = new HashSet<>(tags);
System.out.println("HashSet 去重结果(顺序不保证):" + hashSet);
Set<String> linkedHashSet = new LinkedHashSet<>(tags);
System.out.println("LinkedHashSet 去重并保留插入顺序:" + linkedHashSet);
Set<String> treeSet = new TreeSet<>(tags);
System.out.println("TreeSet 去重并按自然顺序排序:" + treeSet);
System.out.println();
}
/**
* 测试 Queue 和 Deque:
* 1. Queue 按先进先出处理元素
* 2. Deque 可以作为栈使用
*/
private static void testQueueAndDeque() {
System.out.println("===== 3. Queue / Deque:排队处理与栈操作 =====");
Queue<String> printQueue = new ArrayDeque<>();
printQueue.offer("文档A");
printQueue.offer("文档B");
printQueue.offer("文档C");
System.out.println("队首但不移除 peek():" + printQueue.peek());
while (!printQueue.isEmpty()) {
System.out.println("打印完成:" + printQueue.poll());
}
System.out.println("空队列 poll() 返回:" + printQueue.poll());
Deque<String> browserBackStack = new ArrayDeque<>();
browserBackStack.push("首页");
browserBackStack.push("集合框架文章");
browserBackStack.push("ArrayList 文章");
System.out.println("当前页面 peek():" + browserBackStack.peek());
System.out.println("返回上一页,弹出:" + browserBackStack.pop());
System.out.println("返回后所在页面:" + browserBackStack.peek());
System.out.println();
}
/**
* 测试 PriorityQueue:
* 数值越大的任务,优先级越高,越先处理。
*/
private static void testPriorityQueue() {
System.out.println("===== 4. PriorityQueue:按优先级处理任务 =====");
Queue<Task> tasks = new PriorityQueue<>(
Comparator.comparingInt(Task::getPriority).reversed()
);
tasks.offer(new Task("修复线上故障", 100));
tasks.offer(new Task("回复普通邮件", 10));
tasks.offer(new Task("发布版本", 80));
while (!tasks.isEmpty()) {
System.out.println("处理任务:" + tasks.poll());
}
System.out.println();
}
/**
* 测试 Map:
* 1. key 不能重复
* 2. 相同 key 再次 put 会覆盖旧 value
* 3. 不同 Map 实现类的顺序特点不同
*/
private static void testMap() {
System.out.println("===== 5. Map:通过唯一键查找值 =====");
Map<String, Integer> scoreMap = new HashMap<>();
scoreMap.put("张三", 90);
scoreMap.put("李四", 86);
scoreMap.put("张三", 95); // 相同 key 会替换旧 value
System.out.println("张三最新成绩:" + scoreMap.get("张三"));
System.out.println("王五成绩,不存在时给默认值:"
+ scoreMap.getOrDefault("王五", 0));
for (Map.Entry<String, Integer> entry : scoreMap.entrySet()) {
System.out.println(
"学生=" + entry.getKey()
+ ",成绩=" + entry.getValue()
);
}
Map<String, Integer> insertionOrdered = new LinkedHashMap<>();
insertionOrdered.put("first", 1);
insertionOrdered.put("second", 2);
insertionOrdered.put("third", 3);
System.out.println("LinkedHashMap 插入顺序:"
+ insertionOrdered.keySet());
Map<Integer, String> ranking = new TreeMap<>();
ranking.put(3, "铜牌");
ranking.put(1, "金牌");
ranking.put(2, "银牌");
System.out.println("TreeMap 按 key 排序:" + ranking);
}
/**
* 模拟一个待处理任务。
*/
private static class Task {
private final String name;
private final int priority;
private Task(String name, int priority) {
this.name = name;
this.priority = priority;
}
private int getPriority() {
return priority;
}
@Override
public String toString() {
return name + "(优先级=" + priority + ")";
}
}
}
运行后可以观察到:
text
List 中可以同时保存两个"Java书"
Set 会自动去除重复标签
Queue 会按照 文档A → 文档B → 文档C 的顺序处理
Deque 作为栈时,最后访问的页面最先弹出
PriorityQueue 会先处理"修复线上故障"
Map 中张三的成绩会从 90 被更新为 95
LinkedHashMap 会保持 first、second、third 的插入顺序
TreeMap 会按照 1、2、3 的键顺序输出
需要注意:
text
HashSet 和 HashMap 的遍历输出顺序不固定,
不要在代码中依赖它们的打印顺序。
九、常见易混知识点
9.1 Collection 与 Collections 不一样
Collection 是集合接口体系的根接口之一:
java
Collection<String> collection;
Collections 是工具类,提供排序、反转、查找最大值等静态方法:
java
Collections.sort(list);
Collections.reverse(list);
Collections.max(list);
可以简单记忆为:
text
Collection 是容器体系
Collections 是操作容器的工具箱
9.2 Map 不属于 Collection 子接口
虽然 Map 也属于 Java 集合框架,但它保存的是键值对,而 Collection 保存的是单个元素。
java
List<String> list = new ArrayList<>();
Map<String, Integer> map = new HashMap<>();
它们属于两条不同的体系。
总结
Java 集合框架的核心不是记住大量类名,而是理解不同容器解决的问题:
List:保存有顺序、允许重复的数据。Set:保存不能重复的数据。Queue:保存等待处理的数据。Deque:支持两端操作,也可以模拟栈。Map:通过唯一键快速查找对应值。
在常见业务开发中,可以优先掌握:
java
ArrayList
HashSet
ArrayDeque
HashMap
当业务进一步要求保持插入顺序、自动排序或优先级处理时,再选择:
java
LinkedHashSet
TreeSet
PriorityQueue
LinkedHashMap
TreeMap
理解"需要什么能力,再选择什么容器",比单纯背诵集合类更加重要。