1. Java集合框架概述
Java集合框架(Java Collections Framework)是Java语言中用于存储和操作数据集合的一组接口和类。作为Java基础中最核心的API之一,它提供了一套标准化的方法来处理对象集合,大大简化了开发者的工作。
我第一次接触Java集合是在2008年,当时还在用JDK1.4,集合框架已经初具规模但还不够完善。经过十多年的发展,现在的集合框架已经成为Java开发中不可或缺的部分。无论是日常开发还是面试准备,对集合框架的深入理解都是Java程序员的基本功。
注意:Java集合框架位于java.util包中,与数组(Array)不同,集合只能存储对象引用而非基本数据类型(但自动装箱机制可以解决这个问题)
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 集合框架核心接口解析
2.1 Collection接口层次结构
Collection接口是集合框架的根接口,它定义了所有集合类共有的基本操作:
java复制public interface Collection<E> extends Iterable<E> {
int size();
boolean isEmpty();
boolean contains(Object o);
Iterator<E> iterator();
Object[] toArray();
<T> T[] toArray(T[] a);
boolean add(E e);
boolean remove(Object o);
boolean containsAll(Collection<?> c);
boolean addAll(Collection<? extends E> c);
boolean removeAll(Collection<?> c);
boolean retainAll(Collection<?> c);
void clear();
// JDK8新增的stream相关方法...
}
Collection主要有三个子接口:
- List:有序集合,元素可重复
- Set:无序集合,元素不可重复
- Queue:队列,实现先进先出等特定顺序
2.2 Map接口独立体系
Map接口虽然不属于Collection体系,但也是集合框架的重要组成部分。它表示键值对映射:
java复制public interface Map<K,V> {
int size();
boolean isEmpty();
boolean containsKey(Object key);
boolean containsValue(Object value);
V get(Object key);
V put(K key, V value);
V remove(Object key);
void putAll(Map<? extends K, ? extends V> m);
void clear();
Set<K> keySet();
Collection<V> values();
Set<Map.Entry<K, V>> entrySet();
// JDK8新增的默认方法...
}
3. 常用集合类实现详解
3.1 List实现类对比
3.1.1 ArrayList
ArrayList是基于动态数组的实现,是我日常开发中使用最频繁的集合类:
java复制List<String> list = new ArrayList<>();
list.add("Java");
list.add("Collection");
特点:
- 随机访问快(O(1))
- 尾部插入/删除快(O(1))
- 中间插入/删除慢(需要移动元素,O(n))
- 非线程安全
实战经验:初始化时如果知道大概容量,建议指定initialCapacity避免频繁扩容
3.1.2 LinkedList
LinkedList基于双向链表实现:
java复制List<String> linkedList = new LinkedList<>();
linkedList.add("First");
linkedList.add(1, "Second"); // 在指定位置插入
特点:
- 任意位置插入/删除快(O(1))
- 随机访问慢(需要遍历,O(n))
- 实现了Deque接口,可用作队列或栈
3.1.3 Vector
Vector是线程安全的ArrayList,但性能较差,现在基本被Collections.synchronizedList和CopyOnWriteArrayList取代。
3.2 Set实现类对比
3.2.1 HashSet
基于HashMap实现,使用对象的hashCode()和equals()方法判断元素是否相同:
java复制Set<String> set = new HashSet<>();
set.add("Java");
set.add("Java"); // 不会重复添加
特点:
- 无序
- 允许null元素
- 查找效率高(O(1))
3.2.2 LinkedHashSet
HashSet的子类,维护了元素的插入顺序:
java复制Set<String> linkedSet = new LinkedHashSet<>();
linkedSet.add("First");
linkedSet.add("Second");
// 遍历顺序与插入顺序一致
3.2.3 TreeSet
基于TreeMap实现,元素按自然顺序或Comparator排序:
java复制Set<String> treeSet = new TreeSet<>();
treeSet.add("Orange");
treeSet.add("Apple");
// 遍历顺序为Apple, Orange
特点:
- 元素必须实现Comparable或提供Comparator
- 查找效率为O(log n)
3.3 Map实现类对比
3.3.1 HashMap
最常用的Map实现,基于哈希表:
java复制Map<String, Integer> map = new HashMap<>();
map.put("Java", 1);
map.put("Collection", 2);
特点:
- 键值对无序
- 允许null键和null值
- 查找效率高(O(1))
避坑指南:作为键的对象必须正确重写hashCode()和equals()方法
3.3.2 LinkedHashMap
HashMap的子类,维护了键值对的插入顺序或访问顺序:
java复制Map<String, Integer> linkedMap = new LinkedHashMap<>(16, 0.75f, true);
linkedMap.put("First", 1);
linkedMap.put("Second", 2);
linkedMap.get("First"); // 访问后,"First"会移动到末尾
3.3.3 TreeMap
基于红黑树实现,键按自然顺序或Comparator排序:
java复制Map<String, Integer> treeMap = new TreeMap<>();
treeMap.put("Orange", 1);
treeMap.put("Apple", 2);
// 遍历顺序为Apple, Orange
3.3.4 ConcurrentHashMap
线程安全的HashMap实现,比Hashtable性能更好:
java复制Map<String, Integer> concurrentMap = new ConcurrentHashMap<>();
concurrentMap.put("Key", 1);
特点:
- 分段锁机制提高并发性能
- 不允许null键或null值
4. 集合框架高级特性
4.1 迭代器与快速失败机制
所有Collection都实现了Iterable接口,可以使用迭代器遍历:
java复制List<String> list = Arrays.asList("A", "B", "C");
Iterator<String> it = list.iterator();
while(it.hasNext()) {
String element = it.next();
// 处理元素
}
重要:在迭代过程中直接调用集合的add/remove方法会抛出ConcurrentModificationException(快速失败机制)
正确做法是使用迭代器的remove方法:
java复制Iterator<String> it = list.iterator();
while(it.hasNext()) {
String element = it.next();
if(shouldRemove(element)) {
it.remove(); // 安全删除当前元素
}
}
4.2 Comparable与Comparator
TreeSet和TreeMap等有序集合需要元素实现Comparable接口或提供Comparator:
java复制// 实现Comparable
class Person implements Comparable<Person> {
private String name;
public int compareTo(Person other) {
return this.name.compareTo(other.name);
}
}
// 使用Comparator
Comparator<Person> ageComparator = (p1, p2) -> p1.getAge() - p2.getAge();
Set<Person> sortedSet = new TreeSet<>(ageComparator);
4.3 Java 8新增方法
Java 8为集合框架添加了许多实用方法:
java复制List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
// forEach
names.forEach(System.out::println);
// removeIf
names.removeIf(name -> name.length() > 4);
// replaceAll
names.replaceAll(String::toUpperCase);
// Map的compute方法
Map<String, Integer> counts = new HashMap<>();
counts.compute("Java", (k, v) -> v == null ? 1 : v + 1);
5. 集合框架性能优化
5.1 初始化容量设置
对于ArrayList、HashMap等基于数组的集合,合理设置初始容量可以避免频繁扩容:
java复制// 预计有1000个元素,负载因子0.75
Map<String, Integer> map = new HashMap<>(1333); // 1000/0.75 ≈ 1333
5.2 选择合适的集合类
根据使用场景选择最合适的集合类:
- 需要快速随机访问 → ArrayList
- 频繁插入删除 → LinkedList
- 需要去重 → HashSet
- 需要排序 → TreeSet
- 线程安全 → ConcurrentHashMap/CopyOnWriteArrayList
5.3 避免装箱拆箱
对于基本数据类型,使用专门的集合类可以避免自动装箱拆箱的性能损耗:
java复制// 使用IntStream而不是List<Integer>
IntStream.range(0, 100).sum();
6. 常见面试问题解析
6.1 ArrayList和LinkedList的区别
| 特性 | ArrayList | LinkedList |
|---|---|---|
| 底层结构 | 动态数组 | 双向链表 |
| 随机访问 | O(1) | O(n) |
| 头部插入/删除 | O(n) | O(1) |
| 尾部插入/删除 | O(1) | O(1) |
| 内存占用 | 较小(仅数组) | 较大(节点对象) |
6.2 HashMap的工作原理
- 计算键的hashCode()
- 通过哈希函数计算桶位置(index = (n-1) & hash)
- 如果桶为空,直接插入
- 如果桶不为空,遍历链表/红黑树:
- 找到相同键则替换值
- 否则添加到链表/树中
- 如果链表长度超过8且数组长度≥64,链表转为红黑树
- 当元素数量超过阈值(容量×负载因子)时扩容
6.3 ConcurrentHashMap的线程安全实现
JDK1.7及之前:
- 分段锁(Segment),每个段相当于一个HashMap
- 并发度等于段数
JDK1.8及之后:
- 取消分段锁
- 使用CAS+synchronized保证线程安全
- 锁的粒度更小(单个桶或树节点)
7. 实际开发中的经验分享
7.1 集合判空的正确方式
不要使用size()==0判断集合是否为空:
java复制// 不好
if (list.size() == 0) { ... }
// 推荐
if (list.isEmpty()) { ... }
// 最好(可以处理null)
if (CollectionUtils.isEmpty(list)) { ... } // Apache Commons或Spring
7.2 集合转数组的陷阱
直接使用toArray()可能得到Object[],无法强制转换:
java复制List<String> list = Arrays.asList("A", "B");
// 错误方式
String[] array = (String[]) list.toArray(); // ClassCastException
// 正确方式
String[] array = list.toArray(new String[0]);
7.3 使用Collections工具类
Collections提供了许多实用方法:
java复制// 不可变集合
List<String> unmodifiable = Collections.unmodifiableList(list);
// 同步集合
List<String> synchronizedList = Collections.synchronizedList(list);
// 排序
Collections.sort(list);
// 二分查找(必须先排序)
int index = Collections.binarySearch(sortedList, key);
7.4 Java 9+的集合工厂方法
Java 9引入了更简洁的集合创建方式:
java复制// 不可变集合
List<String> list = List.of("A", "B", "C");
Set<String> set = Set.of("A", "B");
Map<String, Integer> map = Map.of("A", 1, "B", 2);
// 注意:这些集合不可修改,且不允许null元素
8. 集合框架的演进与未来
Java集合框架从JDK1.2引入至今,经历了多次重要更新:
- JDK5:泛型支持
- JDK7:钻石操作符(<>)简化泛型声明
- JDK8:Stream API、Lambda表达式支持
- JDK9:集合工厂方法
- JDK10:不可变集合的copyOf方法
- JDK16:新增toList()等Stream终端操作
在实际项目中,我发现很多开发者只停留在基本使用层面,对集合的底层实现和最佳实践了解不够深入。掌握集合框架不仅能写出更高效的代码,也能在系统设计时做出更合理的选择。
