Java 集合入门:从基础到实战的完整知识指南
在 Java 编程中,处理批量数据是高频需求。数组虽能存储数据,但存在长度固定、操作繁琐等局限。集合(Collections) 作为 Java 提供的灵活数据容器,完美解决了这些问题 —— 它支持动态扩容,提供丰富的增删改查方法,是处理多元素数据的核心工具。今天就带大家从零梳理集合体系,重点解析 Collection 接口、Map 接口、二者差异及相关工具类,新手也能轻松上手。
一、集合基础:什么是集合?为什么用集合?
1. 集合的定义
集合是 java.util
包下用于存储多个对象的容器(注意:集合不能直接存基本数据类型,需通过包装类转换)。它隐藏了底层数据结构(如数组、链表、哈希表)的实现细节,提供统一的操作接口,让开发者无需关心 “如何存储”,只需专注 “如何使用”。
2. 集合 vs 数组:核心优势对比
特性 | 数组(Array) | 集合(Collection/Map) |
---|---|---|
长度特性 | 长度固定,创建后不可修改 | 长度动态可变,自动扩容 |
存储类型 | 仅支持同一类型元素 | 可存储不同类型对象(建议统一类型) |
操作能力 | 仅支持索引访问,无内置方法 | 提供增删改查、排序、遍历等方法 |
存储对象 | 可存基本类型或对象 | 仅存对象(基本类型需装箱) |
实例:数组的局限与集合的便捷性
// 数组:添加元素需手动扩容,操作繁琐
int[] arr = new int[3];
arr[0] = 1;
arr[1] = 2;
arr[2] = 3;
// 想添加第4个元素,需新建数组并复制
int[] newArr = new int[arr.length + 1];
System.arraycopy(arr, 0, newArr, 0, arr.length);
newArr[3] = 4;// 集合:动态扩容,添加元素直接调用方法
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
list.add(4); // 无需关心容量,直接添加
System.out.println("集合元素:" + list); // 输出:[1, 2, 3, 4]
二、集合体系核心:两大顶层接口
Java 集合体系以 Collection
接口和 Map
接口为核心,二者分支覆盖了所有常用数据结构。先通过简化体系图建立整体认知:
java.util
├─ Collection(存储单个元素的集合)
│ ├─ List(有序、可重复)
│ │ ├─ ArrayList(数组实现,查询快)
│ │ └─ LinkedList(链表实现,增删快)
│ ├─ Set(无序、不可重复)
│ │ ├─ HashSet(哈希表实现,查询快)
│ │ └─ TreeSet(红黑树实现,可排序)
│ └─ Queue(队列,先进先出)
│ └─ LinkedList(兼作队列实现)
└─ Map(存储键值对的集合)├─ HashMap(哈希表实现,查询快)├─ LinkedHashMap(链表+哈希表,有序)└─ TreeMap(红黑树实现,可排序)
三、Collection 接口:存储单个元素的 “线性容器”
Collection
接口是所有单个元素集合的父接口,定义了一套统一的操作规范,其子类(List、Set)需实现这些方法。
1. Collection 接口的常用方法
无论 List 还是 Set,都支持以下核心操作(以 List 为例演示):
方法名 | 功能 |
---|---|
add(E e) | 添加元素,返回是否成功 |
remove(Object o) | 删除指定元素,返回是否成功 |
contains(Object o) | 判断是否包含指定元素 |
size() | 获取元素个数 |
isEmpty() | 判断集合是否为空 |
clear() | 清空所有元素 |
iterator() | 获取迭代器,用于遍历 |
实例:Collection 方法的基本使用
import java.util.ArrayList;
import java.util.Collection;public class CollectionDemo {public static void main(String[] args) {// 创建Collection实现类对象(ArrayList)Collection<String> coll = new ArrayList<>();// 添加元素coll.add("Java");coll.add("Python");coll.add("C++");System.out.println("添加后:" + coll); // [Java, Python, C++]// 判断是否包含元素System.out.println("包含Java?" + coll.contains("Java")); // true// 删除元素coll.remove("Python");System.out.println("删除后:" + coll); // [Java, C++]// 遍历集合(增强for循环)System.out.print("遍历元素:");for (String lang : coll) {System.out.print(lang + " "); // Java C++ }// 清空集合coll.clear();System.out.println("\n清空后为空?" + coll.isEmpty()); // true}
}
2. Collection 的核心子接口:List 与 Set
Collection 的两大子接口特性差异显著,决定了不同的使用场景:
(1)List 接口:有序、可重复的集合
“有序” 指元素存储顺序与添加顺序一致;“可重复” 指允许存储相同元素(包括null)。常用实现类为 ArrayList
和 LinkedList
。
实现类 | 底层结构 | 优势 | 劣势 | 适用场景 |
---|---|---|---|---|
ArrayList | 动态数组 | 随机访问快(索引定位) | 增删慢(需移动元素) | 查多改少(如数据展示) |
LinkedList | 双向链表 | 增删快(仅改指针) | 随机访问慢(需遍历) | 增删多查少(如队列) |
实例:ArrayList 与 LinkedList 的差异
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;public class ListDemo {public static void main(String[] args) {// ArrayList:查询快List<String> arrayList = new ArrayList<>();arrayList.add("A");arrayList.add("B");String elem = arrayList.get(1); // 直接通过索引获取,效率高System.out.println("ArrayList索引1的元素:" + elem); // B// LinkedList:增删快List<String> linkedList = new LinkedList<>();linkedList.add("X");linkedList.add("Y");linkedList.add(1, "Z"); // 在中间插入,仅修改指针System.out.println("LinkedList插入后:" + linkedList); // [X, Z, Y]}
}
(2)Set 接口:无序、不可重复的集合
“无序” 指元素存储顺序与添加顺序无关(HashSet);“不可重复” 指通过 equals()
和 hashCode()
判断元素是否相同,重复元素会被过滤。常用实现类为 HashSet
和 TreeSet
。
实现类 | 底层结构 | 特性 | 适用场景 |
---|---|---|---|
HashSet | 哈希表 | 无序、查询快 | 去重、快速查找 |
TreeSet | 红黑树 | 可排序(自然 / 自定义) | 需排序的去重场景 |
实例:Set 的去重特性
import java.util.HashSet;
import java.util.Set;public class SetDemo {public static void main(String[] args) {Set<Integer> set = new HashSet<>();set.add(10);set.add(20);set.add(10); // 重复元素,添加失败set.add(30);System.out.println("Set集合元素:" + set); // [10, 20, 30](无序、去重)}
}
四、Map 接口:存储键值对的 “字典容器”
Map
接口与 Collection
接口平级,专门存储键值对(Key-Value)数据,类似现实中的字典 ——“键(Key)” 唯一,“值(Value)” 可重复,通过键能快速定位值。
1. Map 接口的核心特性
- 键唯一:同一 Map 中不能有重复键,重复添加会覆盖原 value;
- 值可重复:不同键可对应相同值;
- 键值关联:查询效率依赖底层结构(如 HashMap 查询时间复杂度为 O(1))。
2. Map 接口的常用方法
方法名 | 功能 |
---|---|
put(K key, V value) | 添加键值对,返回旧 value |
get(Object key) | 通过键获取值,无则返回 null |
remove(Object key) | 通过键删除键值对,返回旧 value |
containsKey(K key) | 判断是否包含指定键 |
keySet() | 获取所有键的 Set 集合 |
entrySet() | 获取所有键值对的 Set 集合 |
size()/isEmpty() | 元素个数 / 是否为空 |
实例:Map 的基本操作与遍历
import java.util.HashMap;
import java.util.Map;public class MapDemo {public static void main(String[] args) {// 创建Map实现类对象(HashMap)Map<String, Integer> scoreMap = new HashMap<>();// 添加键值对scoreMap.put("张三", 90);scoreMap.put("李四", 85);scoreMap.put("张三", 95); // 重复键,覆盖原valueSystem.out.println("添加后:" + scoreMap); // {张三=95, 李四=85}// 通过键获取值System.out.println("张三的分数:" + scoreMap.get("张三")); // 95// 遍历Map(推荐entrySet方式,效率高)System.out.print("键值对遍历:");for (Map.Entry<String, Integer> entry : scoreMap.entrySet()) {String key = entry.getKey();Integer value = entry.getValue();System.out.print(key + ":" + value + " "); // 张三:95 李四:85 }}
}
3. Map 的常用实现类
实现类 | 底层结构 | 特性 | 适用场景 |
---|---|---|---|
HashMap | 哈希表 | 无序、查询快 | 普通键值对存储(最常用) |
LinkedHashMap | 链表 + 哈希表 | 有序(添加顺序) | 需保持插入顺序的场景 |
TreeMap | 红黑树 | 按键排序 | 需排序的键值对场景 |
五、核心对比:Collection 与 Map 的区别
很多初学者容易混淆 Collection 和 Map,二者核心差异体现在存储结构和使用场景:
对比维度 | Collection 接口 | Map 接口 |
---|---|---|
存储单元 | 单个元素(E) | 键值对(Key-Value) |
核心特性 | List 有序可重复 / Set 无序不可重复 | 键唯一、值可重复 |
遍历方式 | 增强 for / 迭代器 | 遍历键 / 值 / 键值对 |
核心方法 | add(E)/remove(Object) | put(K,V)/get(K) |
使用场景 | 存储独立元素(如列表、集合) | 存储键值关联数据(如配置表) |
一句话总结:存 “单个元素的集合” 用 Collection,存 “键值对应的数据” 用 Map。
六、集合工具类:Collections(带s的工具类)
java.util.Collections
是集合的 “辅助工具”——所有方法都是静态的,无需创建对象,提供排序、查找、同步化等便捷操作,专门用于处理 Collection 和 Map。
1. Collections 的常用方法
(1)排序与查找
sort(List<T> list)
:自然排序(元素需实现 Comparable);binarySearch(List<?> list, Object key)
:二分查找(需先排序);max(Collection<?> coll)/min(Collection<?> coll)
:获取最大 / 最小值。
(2)其他实用方法
reverse(List<?> list)
:反转集合元素;shuffle(List<?> list)
:随机打乱元素;synchronizedList(List<T> list)
:将集合转为线程安全的。
实例:Collections 工具类的使用
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;public class CollectionsToolDemo {public static void main(String[] args) {List<Integer> list = new ArrayList<>();list.add(3);list.add(1);list.add(2);System.out.println("原始集合:" + list); // [3, 1, 2]// 自然排序Collections.sort(list);System.out.println("排序后:" + list); // [1, 2, 3]// 二分查找int index = Collections.binarySearch(list, 2);System.out.println("元素2的索引:" + index); // 1// 随机打乱Collections.shuffle(list);System.out.println("打乱后:" + list); // 如 [2, 3, 1]}
}
2. 关键区别:Collection 与 Collections
这是初学者的高频坑点,二者仅差一个s,但本质完全不同:
对比维度 | Collection(无s) | Collections(有s) |
---|---|---|
类型 | 接口(Interface) | 工具类(Class) |
核心作用 | 定义集合的顶层规范 | 提供操作集合的静态方法 |
使用方式 | 被子类实现(如 ArrayList) | 直接调用静态方法(如 Collections.sort()) |
方法特性 | 抽象方法,需子类实现 | 静态方法,无需创建对象 |
一句话区分:Collection 是 “集合的模板”,Collections 是 “操作集合的工具”。
七、避坑指南与总结
1. 常见坑点
- 集合存储的是对象引用:修改集合外的对象,集合内的元素也会变化;
- String 的不可变性与集合:
Set<String>
中添加new String("a")
和"a"
会去重(因equals()
返回 true); - HashMap 的键需重写
equals()
和hashCode()
:否则无法正确判断键的唯一性。
2. 集合选择技巧
- 需有序可重复:用
ArrayList
(查多)或LinkedList
(增删多); - 需无序去重:用
HashSet
;需排序去重:用TreeSet
; - 需键值关联:用
HashMap
(普通场景)、LinkedHashMap
(需顺序)、TreeMap
(需排序); - 需线程安全:用
Vector
(List)、Hashtable
(Map)或Collections.synchronizedXXX()
。
希望这篇文章可以让你掌握接口和实现类的特性。