Java集合框架是Java编程中最常用的API之一,本文将全面深入地讲解集合框架的核心概念、常用实现类、使用场景以及最佳实践。
1. 集合框架概述
1.1 什么是集合框架?
Java集合框架(Java Collections Framework)是一组用于存储和操作对象组的数据结构和算法的统一架构。它提供了丰富的数据结构实现,如列表(List)、集合(Set)、队列(Queue)和映射(Map)等。
集合框架的主要优点:
- 提高代码复用性:提供了标准化的数据结构和算法
- 提高代码质量:经过严格测试,性能优异
- 降低学习成本:统一的API设计,学习一次即可掌握多种数据结构
- 提高开发效率:开箱即用,无需从零实现
1.2 集合框架核心接口
Java集合框架的核心接口结构如下:
Collection(集合根接口)
├── List(有序、可重复)
│ ├── ArrayList(数组实现)
│ ├── LinkedList(链表实现)
│ └── Vector(线程安全的数组实现)
└── Set(无序、不可重复)
├── HashSet(哈希表实现)
├── LinkedHashSet(链表+哈希表,有序)
└── TreeSet(红黑树实现,有序)
Map(键值对根接口)
├── HashMap(哈希表实现)
├── LinkedHashMap(链表+哈希表,有序)
├── TreeMap(红黑树实现,有序)
└── Hashtable(线程安全的哈希表)
2. Collection接口详解
2.1 Collection接口概述
Collection是集合框架的根接口,定义了集合的基本操作方法:
java
public interface Collection<E> extends Iterable<E> {
// 基本操作
int size();
boolean isEmpty();
boolean contains(Object o);
boolean add(E e);
boolean remove(Object o);
// 批量操作
boolean addAll(Collection<? extends E> c);
boolean containsAll(Collection<?> c);
boolean removeAll(Collection<?> c);
boolean retainAll(Collection<?> c);
void clear();
// 数组转换
Object[] toArray();
<T> T[] toArray(T[] a);
// 迭代器
Iterator<E> iterator();
}
2.2 遍历集合的四种方式
java
import java.util.*;
public class CollectionTraversal {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("Java");
list.add("Python");
list.add("C++");
list.add("JavaScript");
// 方式1:for循环(仅List)
System.out.println("=== 方式1:for循环 ===");
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
// 方式2:增强for循环
System.out.println("\n=== 方式2:增强for循环 ===");
for (String language : list) {
System.out.println(language);
}
// 方式3:Iterator迭代器
System.out.println("\n=== 方式3:Iterator迭代器 ===");
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
String lang = iterator.next();
System.out.println(lang);
}
// 方式4:Java 8+ forEach
System.out.println("\n=== 方式4:forEach ===");
list.forEach(System.out::println);
}
}
3. List接口详解
3.1 ArrayList详解
ArrayList是最常用的List实现类,基于动态数组实现。
特点:
- 随机访问效率高(O(1))
- 尾部插入删除效率高(均摊O(1))
- 中间插入删除效率低(O(n))
- 线程不安全
java
import java.util.*;
public class ArrayListDemo {
public static void main(String[] args) {
// 创建ArrayList
ArrayList<String> arrayList = new ArrayList<>();
// 添加元素
arrayList.add("Java");
arrayList.add("Python");
arrayList.add("C++");
arrayList.add("JavaScript");
System.out.println("初始大小: " + arrayList.size()); // 4
// 指定位置插入
arrayList.add(2, "Go");
System.out.println("插入后: " + arrayList); // [Java, Python, Go, C++, JavaScript]
// 获取元素
String first = arrayList.get(0);
System.out.println("第一个元素: " + first); // Java
// 删除元素
arrayList.remove("C++");
arrayList.remove(0); // 按索引删除
// 查找元素
int index = arrayList.indexOf("Python");
boolean contains = arrayList.contains("Java");
// 转换为数组
String[] array = arrayList.toArray(new String[0]);
// 批量操作
List<String> anotherList = Arrays.asList("Ruby", "PHP");
arrayList.addAll(anotherList);
// 清空
arrayList.clear();
}
}
3.2 LinkedList详解
LinkedList基于双向链表实现,同时实现了List和Deque接口。
特点:
- 插入删除效率高(O(1))
- 随机访问效率低(O(n))
- 线程不安全
- 可作为队列、栈、双端队列使用
java
import java.util.*;
public class LinkedListDemo {
public static void main(String[] args) {
LinkedList<Integer> linkedList = new LinkedList<>();
// 作为List使用
linkedList.add(1);
linkedList.add(2);
linkedList.add(3);
// 作为栈使用(后进先出)
linkedList.push(0); // 添加到头部
linkedList.pop(); // 从头部删除并返回
// 作为队列使用(先进先出)
linkedList.offer(4); // 添加到尾部
linkedList.poll(); // 从头部删除
// 双端队列操作
linkedList.addFirst(-1);
linkedList.addLast(100);
linkedList.removeFirst();
linkedList.removeLast();
// 获取但不移除
System.out.println("第一个元素: " + linkedList.getFirst());
System.out.println("最后一个元素: " + linkedList.getLast());
System.out.println("LinkedList: " + linkedList);
}
}
3.3 ArrayList vs LinkedList 选择
| 场景 | 推荐使用 | 原因 |
|---|---|---|
| 随机访问多 | ArrayList | 随机访问O(1) |
| 插入删除多 | LinkedList | 插入删除O(1) |
| 内存敏感 | ArrayList | 内存开销小 |
| 需要栈/队列 | LinkedList | 提供了相关方法 |
4. Set接口详解
4.1 HashSet详解
HashSet是最常用的Set实现类,基于哈希表实现。
特点:
- 元素不可重复
- 可以存储null
- 不保证顺序(无序)
- 线程不安全
- 增删改查均为O(1)
java
import java.util.*;
public class HashSetDemo {
public static void main(String[] args) {
HashSet<String> hashSet = new HashSet<>();
// 添加元素
hashSet.add("Java");
hashSet.add("Python");
hashSet.add("C++");
hashSet.add("Java"); // 重复元素,不会添加
hashSet.add(null); // 可以存储null
System.out.println("HashSet大小: " + hashSet.size()); // 4
System.out.println("HashSet内容: " + hashSet); // [null, Java, Python, C++](无序)
// 查找元素
boolean contains = hashSet.contains("Java"); // true
// 删除元素
hashSet.remove("C++");
// HashSet的去重原理:使用hashCode()和equals()方法
}
}
4.2 LinkedHashSet详解
LinkedHashSet是HashSet的子类,在哈希表基础上增加了双向链表来维护顺序。
特点:
- 元素不可重复
- 保持插入顺序
- 性能略低于HashSet
java
import java.util.*;
public class LinkedHashSetDemo {
public static void main(String[] args) {
LinkedHashSet<String> linkedHashSet = new LinkedHashSet<>();
linkedHashSet.add("Java");
linkedHashSet.add("Python");
linkedHashSet.add("C++");
linkedHashSet.add("Java"); // 重复元素,不会添加
System.out.println("LinkedHashSet(保持插入顺序): " + linkedHashSet);
// 输出: [Java, Python, C++]
// 应用场景:需要去重且保持顺序
List<String> listWithDuplicates = Arrays.asList("A", "B", "A", "C", "B", "D");
LinkedHashSet<String> uniqueOrdered = new LinkedHashSet<>(listWithDuplicates);
System.out.println("去重后的顺序: " + uniqueOrdered); // [A, B, C, D]
}
}
4.3 TreeSet详解
TreeSet基于红黑树实现,可以对元素进行排序。
特点:
- 元素不可重复
- 可以排序(自然排序或自定义Comparator)
- 增删改查均为O(log n)
- 不允许存储null
java
import java.util.*;
public class TreeSetDemo {
public static void main(String[] args) {
// 自然排序(String实现了Comparable接口)
TreeSet<String> treeSet = new TreeSet<>();
treeSet.add("Java");
treeSet.add("Python");
treeSet.add("C++");
treeSet.add("Go");
System.out.println("TreeSet(自然排序): " + treeSet);
// 输出: [C++, Go, Java, Python](按字母顺序)
// TreeSet特有方法
System.out.println("第一个元素: " + treeSet.first()); // C++
System.out.println("最后一个元素: " + treeSet.last()); // Python
System.out.println("小于Python的元素: " + treeSet.headSet("Python"));
System.out.println("大于等于Java的元素: " + treeSet.tailSet("Java"));
}
}
5. Map接口详解
5.1 HashMap详解
HashMap是最常用的Map实现类,基于哈希表实现。
特点:
- 键值对存储
- 键不可重复,值可以重复
- 允许存储null键和null值
- 线程不安全
- 增删改查均为O(1)
java
import java.util.*;
public class HashMapDemo {
public static void main(String[] args) {
HashMap<String, Integer> hashMap = new HashMap<>();
// 添加键值对
hashMap.put("Java", 1);
hashMap.put("Python", 2);
hashMap.put("C++", 3);
hashMap.put("Java", 4); // 键重复,值覆盖
System.out.println("HashMap内容: " + hashMap);
// 获取值
Integer javaValue = hashMap.get("Java"); // 4
Integer unknown = hashMap.get("Unknown"); // null
// 获取默认值
Integer defaultValue = hashMap.getOrDefault("Unknown", 0); // 0
// 遍历HashMap
hashMap.forEach((k, v) -> System.out.println(k + " = " + v));
// 删除键值对
hashMap.remove("C++");
}
}
5.2 HashMap的底层原理
HashMap的重要常量:
- 默认初始容量:16
- 负载因子:0.75
- 当容量使用率达到75%时,会进行扩容(容量翻倍)
添加元素的过程:
- 计算key的hash值
- 根据hash值计算在数组中的索引位置
- 如果该位置为空,直接放入
- 如果该位置不为空(发生哈希冲突):
- 如果key相等(hash相同且equals为true),覆盖value
- 如果key不等,形成链表或红黑树(Java 8+)
5.3 LinkedHashMap详解
LinkedHashMap是HashMap的子类,在哈希表基础上增加了双向链表来维护顺序。
特点:
- 键值对存储
- 保持插入顺序或访问顺序
- 性能略低于HashMap
java
import java.util.*;
public class LinkedHashMapDemo {
public static void main(String[] args) {
// 插入顺序
LinkedHashMap<String, Integer> insertOrderMap = new LinkedHashMap<>();
insertOrderMap.put("Java", 1);
insertOrderMap.put("Python", 2);
insertOrderMap.put("C++", 3);
System.out.println("插入顺序: " + insertOrderMap);
// 输出: {Java=1, Python=2, C++=3}
// 访问顺序(LRU缓存常用)
LinkedHashMap<String, Integer> accessOrderMap = new LinkedHashMap<>(16, 0.75f, true);
accessOrderMap.put("Java", 1);
accessOrderMap.put("Python", 2);
accessOrderMap.put("C++", 3);
accessOrderMap.get("Java"); // 访问Java,移到末尾
System.out.println("访问顺序: " + accessOrderMap);
// LRU缓存示例
LinkedHashMap<String, Integer> lruCache = new LinkedHashMap<>(3) {
@Override
protected boolean removeEldestEntry(Map.Entry eldest) {
return size() > 3;
}
};
lruCache.put("A", 1);
lruCache.put("B", 2);
lruCache.put("C", 3);
lruCache.put("D", 4); // 自动删除最老的A
System.out.println("LRU缓存: " + lruCache);
// 输出: {B=2, C=3, D=4}
}
}
5.4 TreeMap详解
TreeMap基于红黑树实现,可以对键进行排序。
特点:
- 键值对存储
- 键不可重复
- 可以排序(自然排序或自定义Comparator)
- 增删改查均为O(log n)
java
import java.util.*;
public class TreeMapDemo {
public static void main(String[] args) {
TreeMap<String, Integer> treeMap = new TreeMap<>();
treeMap.put("Java", 1);
treeMap.put("Python", 2);
treeMap.put("C++", 3);
System.out.println("TreeMap(自然排序): " + treeMap);
// 输出: {C++=3, Java=1, Python=2}
// TreeMap特有方法
System.out.println("第一个键: " + treeMap.firstKey()); // C++
System.out.println("最后一个键: " + treeMap.lastKey()); // Python
System.out.println("小于Python的键: " + treeMap.headMap("Python"));
System.out.println("大于等于Java的键: " + treeMap.tailMap("Java"));
}
}
6. 集合工具类Collections
6.1 排序和查找操作
java
import java.util.*;
public class CollectionsDemo {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("Java");
list.add("Python");
list.add("C++");
// 排序
Collections.sort(list);
System.out.println("排序后: " + list);
Collections.reverse(list);
System.out.println("反转后: " + list);
Collections.shuffle(list);
System.out.println("打乱后: " + list);
// 查找
Collections.sort(list);
int index = Collections.binarySearch(list, "Python");
System.out.println("Python的索引: " + index);
// 最大值/最小值
System.out.println("最大值: " + Collections.max(list));
System.out.println("最小值: " + Collections.min(list));
}
}
6.2 同步控制和不可修改集合
java
import java.util.*;
public class CollectionsSync {
public static void main(String[] args) {
// 同步集合
List<String> synchronizedList = Collections.synchronizedList(new ArrayList<>());
Set<String> synchronizedSet = Collections.synchronizedSet(new HashSet<>());
Map<String, Integer> synchronizedMap = Collections.synchronizedMap(new HashMap<>());
// 不可修改集合
List<String> unmodifiableList = Collections.unmodifiableList(Arrays.asList("A", "B", "C"));
// 单例集合
List<String> singletonList = Collections.singletonList("唯一元素");
Set<String> singletonSet = Collections.singleton("唯一元素");
Map<String, Integer> singletonMap = Collections.singletonMap("key", 1);
// 空集合
List<String> emptyList = Collections.emptyList();
Set<String> emptySet = Collections.emptySet();
Map<String, Integer> emptyMap = Collections.emptyMap();
}
}
7. 集合最佳实践
7.1 选择正确的集合类型
java
public class ChooseRightCollection {
public static void main(String[] args) {
// 需要根据索引快速访问元素 → ArrayList
List<String> list = new ArrayList<>();
// 需要在中间频繁插入/删除 → LinkedList
List<String> linkedList = new LinkedList<>();
// 需要去重 → HashSet
Set<String> set = new HashSet<>();
// 需要保持顺序 → LinkedHashSet
Set<String> orderedSet = new LinkedHashSet<>();
// 需要排序 → TreeSet
Set<String> sortedSet = new TreeSet<>();
// 需要键值对 → HashMap
Map<String, Integer> map = new HashMap<>();
// 需要LRU缓存 → LinkedHashMap
Map<String, Integer> lruCache = new LinkedHashMap<>(3) {
@Override
protected boolean removeEldestEntry(Map.Entry eldest) {
return size() > 3;
}
};
}
}
7.2 避免常见错误
java
import java.util.*;
public class CollectionMistakes {
public static void main(String[] args) {
// 错误1:在循环中删除元素(正确方式)
List<String> list = new ArrayList<>(Arrays.asList("A", "B", "C", "B", "D"));
// 正确方式1:使用Iterator
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
if ("B".equals(iterator.next())) {
iterator.remove();
}
}
// 正确方式2:使用removeIf(Java 8+)
list = new ArrayList<>(Arrays.asList("A", "B", "C", "B", "D"));
list.removeIf("B"::equals);
// 错误2:修改作为key的对象
// 避免修改HashMap/HashSet中作为key的对象的hashCode
// 错误3:集合与数组混淆
String[] array = new String[]{"A", "B", "C"};
List<String> listFromArray = Arrays.asList(array); // 固定大小
List<String> mutableList = new ArrayList<>(Arrays.asList(array)); // 可变大小
}
}
7.3 性能优化技巧
java
public class CollectionPerformance {
public static void main(String[] args) {
// 技巧1:指定初始容量(减少扩容次数)
ArrayList<String> list = new ArrayList<>(1000);
HashMap<String, Integer> map = new HashMap<>(1000, 0.8f);
// 技巧2:使用接口类型声明
List<String> list = new ArrayList<>(); // 推荐
Map<String, Integer> map = new HashMap<>(); // 推荐
// 技巧3:批量操作比循环操作高效
List<String> list1 = new ArrayList<>(Arrays.asList("A", "B"));
List<String> list2 = new ArrayList<>(Arrays.asList("C", "D"));
list1.addAll(list2); // 高效
// 技巧4:使用正确的数据结构
Set<String> set = new HashSet<>(); // O(1)contains
// 不要在List中频繁使用contains(O(n))
}
}
8. 总结
核心要点回顾
-
List:有序、可重复
- ArrayList:随机访问多
- LinkedList:插入删除多
-
Set:无序、不可重复
- HashSet:通用场景
- LinkedHashSet:保持顺序
- TreeSet:需要排序
-
Map:键值对
- HashMap:通用场景
- LinkedHashMap:保持顺序/LRU
- TreeMap:需要排序键