一、Java集合框架全景图
1.1 核心接口层次结构
graph TDA[Iterable] --> B[Collection]B --> C1[List]B --> C2[Set]B --> C3[Queue]C1 --> D1[ArrayList]C1 --> D2[LinkedList]C2 --> E1[HashSet]C2 --> E2[TreeSet]C3 --> F1[PriorityQueue]G[Map] --> H1[HashMap]G --> H2[TreeMap]G --> H3[ConcurrentHashMap]
1.2 核心接口说明
接口 | 特点 | 典型实现类 |
---|---|---|
List | 有序、可重复 | ArrayList, LinkedList |
Set | 无序、唯一 | HashSet, TreeSet |
Queue | 先进先出(FIFO)或优先级队列 | LinkedList, PriorityQueue |
Map | 键值对存储 | HashMap, TreeMap |
Deque | 双端队列 | ArrayDeque |
二、List家族深度剖析
2.1 ArrayList vs LinkedList
特性 | ArrayList | LinkedList |
---|---|---|
底层结构 | 动态数组 | 双向链表 |
随机访问速度 | O(1) | O(n) |
插入删除性能 | 尾部O(1),中间O(n) | 头尾O(1),中间O(n) |
内存占用 | 连续内存,空间浪费少 | 每个元素额外存储两个指针 |
最佳场景 | 高频查询+尾部操作 | 频繁插入删除(尤其是中间) |
代码示例:初始化与遍历
// ArrayList初始化
List<String> arrayList = new ArrayList<>();
arrayList.add("Java");
arrayList.add("Python");// LinkedList初始化
List<String> linkedList = new LinkedList<>();
linkedList.add("C++");
linkedList.addFirst("Go"); // 链表特有方法// 通用遍历方式(JDK8+)
arrayList.forEach(System.out::println);
三、Set家族的奥秘
3.1 HashSet vs TreeSet
特性 | HashSet | TreeSet |
---|---|---|
底层实现 | HashMap | 红黑树 |
元素顺序 | 无序 | 自然顺序或Comparator排序 |
时间复杂度 | 添加/删除/查找平均O(1) | 所有操作O(log n) |
允许null值 | 是 | 否(除非Comparator支持) |
代码示例:自定义对象的HashSet使用
class Student {String id;String name;// 必须重写equals和hashCode!@Overridepublic boolean equals(Object o) { /*...*/ }@Overridepublic int hashCode() { /*...*/ }
}Set<Student> students = new HashSet<>();
students.add(new Student("1001", "Alice"));
四、Map家族的王者之争
4.1 HashMap底层原理(JDK8+)
-
数组+链表+红黑树结构
-
默认负载因子0.75,扩容阈值=容量×负载因子
-
哈希冲突解决:链表长度≥8时转红黑树,≤6时退化为链表
PUT操作流程示意图:
ConcurrentMap<String, Integer> scores = new ConcurrentHashMap<>();
scores.compute("Alice", (k, v) -> (v == null) ? 1 : v + 1);
五、高级话题与性能优化
5.1 集合初始化容量优化
-
ArrayList:预估数据量避免频繁扩容(默认容量10)
-
HashMap:设置初始容量=预期元素数/0.75 + 1
// 优化示例:预期存储1000个元素 new HashMap<>( (int)(1000/0.75) + 1 );
5.2 遍历方式的性能对比
遍历方式 | ArrayList | LinkedList | HashSet |
---|---|---|---|
for循环 | 最快 | 极慢 | 不支持 |
迭代器 | 快 | 快 | 快 |
forEach+lambda | 快 | 快 | 快 |
5.3 不可变集合(Java 9+)
List<String> immutableList = List.of("A", "B", "C");
Set<Integer> immutableSet = Set.of(1, 2, 3);
Map<String, Integer> immutableMap = Map.of("Key1", 1, "Key2", 2);
六、常见问题与陷阱
6.1 ConcurrentModificationException
错误示例:
List<String> list = new ArrayList<>(Arrays.asList("A", "B"));
for (String s : list) {if ("B".equals(s)) {list.remove(s); // 抛出异常!}
}
解决方案:
-
使用迭代器的
remove()
方法 -
使用
CopyOnWriteArrayList
-
使用Stream过滤(Java8+)
6.2 hashCode()与equals()的契约
-
规则1:两个对象相等(
equals()
返回true)→ 必须具有相同的hashCode()
-
规则2:
hashCode()
相同的对象不一定相等 -
违反后果:在HashSet/HashMap中出现重复元素或丢失元素
七、最佳实践总结
-
选择集合类型的三要素
-
是否需要排序?
-
是否需要唯一性?
-
主要操作类型(查询/插入/删除)?
-
-
线程安全策略
-
无竞争:普通集合
-
低竞争:
Collections.synchronizedXXX()
-
高并发:
ConcurrentHashMap
,CopyOnWriteArrayList
-
-
性能黄金法则
-
预估容量减少扩容
-
避免在循环中频繁创建迭代器
-
复杂对象实现高效的
hashCode()
方法
-