前言
在 Java 开发中,我们经常需要存储和操作一组数据,这时候 “集合” 就成了核心工具。但很多初学者会疑惑:集合和数组都是存数据的,到底有啥区别?今天就从 “数组 vs 集合” 说起,再全面拆解 Java 集合框架的Collection和Map两大体系,帮你彻底搞懂集合的用法和选型。
一、先搞清楚:集合和数组到底有啥区别?
数组是 Java 的基础数据结构,而集合是 Java 提供的 “高级数据容器”,两者核心差异集中在灵活性、功能、存储范围三个维度,直接看对比表更清晰:
| 对比维度 | 数组(Array) | 集合(Collection/Map) |
|---|---|---|
| 长度特性 | 长度固定,初始化后不能修改 | 长度动态,可自动扩容 / 缩容 |
| 存储数据类型 | 只能存 “同一种基本类型 / 引用类型”(如int[]、String[]) | 只能存 “引用类型”(基本类型需用包装类,如Integer),部分集合支持存不同类型(如ArrayList<Object>) |
| 功能方法 | 仅提供 “通过索引访问” 的功能,无自带增删查改方法 | 自带丰富方法(如add()、remove()、contains()、sort()),无需手动实现 |
| 存储范围 | 仅能存 “单值”(无键值对结构) | 支持单值(Collection)和键值对(Map)两种存储结构 |
举个简单例子:如果需要存 10 个学生姓名,用数组的话要先定长度String[] names = new String[10],如果后续要加第 11 个,就得重新创建数组;但用ArrayList的话,直接list.add("新同学")就行,底层会自动扩容,不用管长度。
二、集合框架核心结构:两大顶层接口
Java 集合框架的顶层结构很清晰,主要分为两大体系:
Collection接口:存储 “单值元素” 的集合,所有单值集合(如 List、Set)都继承自它;Map接口:存储 “键值对(Key-Value)” 的集合,键唯一,值可重复,和Collection是完全独立的体系。
先看一张简化的结构示意图(帮你建立整体认知):
三、深入Collection体系:单值集合的用法
Collection是所有单值集合的父接口,定义了通用方法(如add(E e)、remove(Object o)、size()、isEmpty()),但它是 “接口”,不能直接实例化,需要用它的子接口实现类。
1. List 接口:有序、可重复的 “动态数组”
1.1 核心特点:
- 元素有 “索引”(和数组类似),所以有序(存储顺序 = 取出顺序);
- 元素可重复(允许存多个相同值);
- 常用实现类:
ArrayList、LinkedList、Vector。
1.2 三大实现类对比与代码示例:
| 实现类 | 底层结构 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|---|
| ArrayList | 动态数组 | 查询快(通过索引访问) | 增删慢(需移动元素) | 频繁查询、少增删 |
| LinkedList | 双向链表 | 增删快(只需改指针) | 查询慢(需遍历链表) | 频繁增删、少查询 |
| Vector | 动态数组(线程安全) | 线程安全 | 效率低(方法加锁) | 多线程环境(已少用,推荐CopyOnWriteArrayList) |
代码示例:ArrayList 基本用法
import java.util.ArrayList;
import java.util.List;
public class ListDemo {
public static void main(String[] args) {
// 1. 创建ArrayList实例(存储String类型)
List<String> arrayList = new ArrayList<>();
// 2. 增:添加元素
arrayList.add("Java");
arrayList.add("Python");
arrayList.add("Java"); // 允许重复,正常添加
System.out.println("添加后:" + arrayList); // 输出:[Java, Python, Java]
// 3. 查:通过索引获取元素(和数组类似)
String element = arrayList.get(1);
System.out.println("索引1的元素:" + element); // 输出:Python
// 4. 删:删除指定元素(删除第一个匹配的值)
arrayList.remove("Java");
System.out.println("删除后:" + arrayList); // 输出:[Python, Java]
// 5. 遍历:增强for循环(推荐)
for (String s : arrayList) {
System.out.println("遍历元素:" + s);
}
}
}
2. Set 接口:无序、不可重复的 “去重集合”
2.1 核心特点:
- 元素无序(存储顺序≠取出顺序,除非用
LinkedHashSet); - 元素不可重复(底层通过 “哈希值 + equals ()” 保证,相同元素会被过滤);
- 常用实现类:
HashSet、TreeSet、LinkedHashSet。
2.2 三大实现类对比与代码示例:
| 实现类 | 底层结构 | 核心特点 | 适用场景 |
|---|---|---|---|
| HashSet | 哈希表(数组 + 链表 / 红黑树) | 无序、去重、查询快 | 只需去重,不关心顺序 |
| TreeSet | 红黑树 | 有序(按元素自然排序)、去重 | 需要按元素排序 + 去重 |
| LinkedHashSet | 哈希表 + 链表 | 有序(保留插入顺序)、去重 | 需要去重且保留插入顺序 |
代码示例:HashSet 去重与 TreeSet 排序
import java.util.HashSet;
import java.util.TreeSet;
public class SetDemo {
public static void main(String[] args) {
// 1. HashSet:去重+无序
HashSet<Integer> hashSet = new HashSet<>();
hashSet.add(3);
hashSet.add(1);
hashSet.add(3); // 重复元素,会被过滤
System.out.println("HashSet:" + hashSet); // 输出:[1, 3](无序)
// 2. TreeSet:排序+去重(默认自然排序:从小到大)
TreeSet<Integer> treeSet = new TreeSet<>();
treeSet.add(5);
treeSet.add(2);
treeSet.add(5); // 重复元素被过滤
System.out.println("TreeSet:" + treeSet); // 输出:[2, 5](有序)
}
}
3. Queue 接口:先进先出(FIFO)的 “队列”
3.1 核心特点:
- 遵循 “先进先出”(FIFO)原则,类似排队(先到先服务);
- 常用实现类:
LinkedList(兼作队列,底层链表)、PriorityQueue(优先队列,按优先级出队)。
代码示例:LinkedList 实现队列
import java.util.LinkedList;
import java.util.Queue;
public class QueueDemo {
public static void main(String[] args) {
// 用LinkedList实现Queue接口
Queue<String> queue = new LinkedList<>();
// 入队:添加元素到队尾
queue.offer("张三");
queue.offer("李四");
queue.offer("王五");
System.out.println("队列:" + queue); // 输出:[张三, 李四, 王五]
// 出队:移除并返回队头元素
String head = queue.poll();
System.out.println("出队元素:" + head); // 输出:张三
System.out.println("出队后队列:" + queue); // 输出:[李四, 王五]
}
}
四、深入Map体系:键值对集合的用法
Map和Collection完全不同:它存储的是 “键值对(Key-Value)”,比如 “学号 - 学生姓名”“ID - 用户信息”,其中Key 必须唯一(重复会覆盖),Value 可以重复。
1. Map 核心特点与常用实现类
Map的顶层接口是java.util.Map,定义了通用方法(如put(K key, V value)、get(Object key)、remove(Object key)),常用实现类对比:
| 实现类 | 底层结构 | 核心特点 | 适用场景 |
|---|---|---|---|
| HashMap | 哈希表(数组 + 链表 / 红黑树) | 无序、键唯一、线程不安全、效率高 | 单线程环境,需快速键值查询 |
| TreeMap | 红黑树 | 有序(按 Key 排序)、键唯一 | 需要按 Key 排序的键值对场景 |
| LinkedHashMap | 哈希表 + 链表 | 有序(保留插入顺序)、键唯一 | 需要保留键值对插入顺序 |
| HashTable | 哈希表 | 线程安全、已过时 | 多线程环境(推荐用ConcurrentHashMap替代) |
注意:HashMap在 JDK1.8 后优化了底层结构 —— 当链表长度超过 8 时,会转为红黑树,提升查询效率。
2. 代码示例:HashMap 基本用法
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class MapDemo {
public static void main(String[] args) {
// 1. 创建HashMap实例(Key:学号String,Value:姓名String)
Map<String, String> studentMap = new HashMap<>();
// 2. 存:添加键值对(Key重复会覆盖旧Value)
studentMap.put("2023001", "张三");
studentMap.put("2023002", "李四");
studentMap.put("2023001", "张三(更新)"); // Key重复,覆盖旧值
System.out.println("HashMap:" + studentMap);
// 输出:{2023001=张三(更新), 2023002=李四}(无序)
// 3. 查:通过Key获取Value
String name = studentMap.get("2023002");
System.out.println("学号2023002的姓名:" + name); // 输出:李四
// 4. 遍历:两种常用方式
// 方式1:遍历所有Key,再通过Key获取Value
Set<String> keys = studentMap.keySet();
for (String key : keys) {
System.out.println("Key:" + key + ",Value:" + studentMap.get(key));
}
// 方式2:直接遍历键值对(推荐,更高效)
for (Map.Entry<String, String> entry : studentMap.entrySet()) {
System.out.println("Key:" + entry.getKey() + ",Value:" + entry.getValue());
}
}
}
五、集合选型:不同场景该用哪个?
学完集合体系,最关键的是 “选对工具”,这里给大家总结一套选型思路:
-
需要单值存储:用
Collection体系- 要有序、可重复、频繁查询:选
ArrayList; - 要有序、可重复、频繁增删:选
LinkedList; - 要去重、不关心顺序:选
HashSet; - 要去重、且按元素排序:选
TreeSet; - 要先进先出:选
LinkedList(队列)。
- 要有序、可重复、频繁查询:选
-
需要键值对存储:用
Map体系- 单线程、快速查询、不关心顺序:选
HashMap; - 单线程、需要按 Key 排序:选
TreeMap; - 单线程、需要保留插入顺序:选
LinkedHashMap; - 多线程、需要线程安全:选
ConcurrentHashMap(不要用HashTable)。
- 单线程、快速查询、不关心顺序:选
六、总结
Java 集合框架是开发中的 “必备工具包”,核心是Collection(单值)和Map(键值对)两大体系。和数组相比,集合更灵活(动态长度)、功能更丰富(自带增删查改),但要注意:集合只能存引用类型(基本类型需用包装类)。
希望这篇文章能帮你理清集合的脉络,下次写代码时,再也不用纠结 “该用哪个集合” 啦!如果有疑问,欢迎在评论区交流~
&spm=1001.2101.3001.5002&articleId=151688337&d=1&t=3&u=e89c3e3e1a804f75adad3236add1eda6)
5335

被折叠的 条评论
为什么被折叠?



