面试知识库
基础

集合框架总览#

一句话答案#

集合分 Collection(List/Set/Queue)和 Map 两大体系;List 有序可重复,Set 不重复,Map 键值对。fail-fast 迭代时检测 modCountConcurrentModificationExceptionfail-safe(CopyOnWrite/ConcurrentHashMap)基于副本或弱一致不抛异常。

核心要点

一、两大顶层接口

Iterable
└── Collection
    ├── List   ── ArrayList / LinkedList / Vector
    ├── Set    ── HashSet / LinkedHashSet / TreeSet
    └── Queue  ── LinkedList / ArrayDeque / PriorityQueue

Map(独立体系,不属于 Collection)
    ── HashMap / LinkedHashMap / TreeMap / Hashtable / ConcurrentHashMap
plaintext

二、List / Set / Queue 特性

接口有序可重复典型实现
List插入有序、有索引ArrayList(查改)、LinkedList(增删)
Set看实现HashSet(无序)、LinkedHashSet(插入序)、TreeSet(排序)
QueueFIFO/优先级ArrayDeque、PriorityQueue

三、fail-fast 机制

  • 集合内部维护 modCount(修改计数),迭代器创建时记录 expectedModCount
  • 每次 next() 校验两者是否相等,不等则抛 ConcurrentModificationException
  • 触发场景:遍历时直接调用集合的 add/remove(单线程也会触发)、或多线程并发修改。
for (String s : list) {
    if (cond) list.remove(s);   // ❌ 抛 ConcurrentModificationException
}
// ✅ 正确:用迭代器自身的 remove
Iterator<String> it = list.iterator();
while (it.hasNext()) { if (cond) it.remove(); }
java

四、fail-safe 机制

  • CopyOnWriteArrayList:写时复制,迭代基于旧数组快照,不抛异常但读不到最新写入。
  • ConcurrentHashMap:弱一致迭代器,遍历期间的修改可能可见可能不可见,不抛异常。
  • 代价:内存开销(副本)或数据弱一致。

五、HashMap vs Hashtable vs ConcurrentHashMap

维度HashMapHashtableConcurrentHashMap
线程安全✅(全表 synchronized)✅(CAS+桶锁)
null 键值允许各一个 null都不允许都不允许
性能低(整表锁)高(分段/桶级并发)
迭代器fail-fastfail-fastfail-safe(弱一致)
现状主流已淘汰(遗留类)并发场景首选
面试回答(2分钟版)

Java 集合框架有两大顶层接口,一个是 Collection,一个是 Map,Map 不属于 Collection。Collection 下面分三类:List 是有序可重复、有索引的,常用 ArrayList 和 LinkedList;Set 是不允许重复的,HashSet 无序、LinkedHashSet 保持插入顺序、TreeSet 排序;Queue 是队列,比如 ArrayDeque 和优先级队列 PriorityQueue。Map 是键值对结构,常用 HashMap、保持顺序的 LinkedHashMap、排序的 TreeMap,还有线程安全的 ConcurrentHashMap。面试高频的是 fail-fast 机制:集合内部有个 modCount 修改计数器,迭代器创建时记下期望值,每次 next 都校验,如果遍历过程中直接调用集合的 add 或 remove 改了结构,modCount 对不上就抛 ConcurrentModificationException,注意单线程下遍历时删元素也会触发,正确做法是用迭代器自己的 remove。与之相对的是 fail-safe,像 CopyOnWriteArrayList 写时复制、ConcurrentHashMap 弱一致迭代器,它们遍历的是快照或弱一致视图,不会抛异常但可能读不到最新数据。HashMap、Hashtable、ConcurrentHashMap 的对比也常考:HashMap 线程不安全、允许 null 键值;Hashtable 用整表 synchronized 性能差、已经被淘汰;ConcurrentHashMap 用 CAS 加桶级锁,是并发场景的首选。

追问与易错

追问方向:

  • “遍历集合时删除元素为什么报错?”→ 触发 fail-fast,modCount 与迭代器 expectedModCount 不一致;应使用迭代器的 remove 或 removeIf
  • “fail-fast 一定能检测到并发修改吗?”→ 不保证。modCount 非 volatile,只是尽力而为的检测机制,不能用作并发正确性保障
  • “ArrayList 遍历删除,倒序 for 循环可以吗?”→ 可以。用索引倒序删不依赖迭代器,不会触发 fail-fast
  • “Hashtable 为什么被淘汰?”→ 整张表加 synchronized 锁粒度太粗、并发性能差,并发场景应用 ConcurrentHashMap
  • “Iterator 和 ListIterator 区别?”→ ListIterator 仅用于 List,支持双向遍历、add、set,并能拿到索引

易错点:

  • ❌ “fail-fast 是为了保证线程安全”——它只是检测机制,不保证安全
  • ❌ “Set 都是无序的”——LinkedHashSet 保插入序、TreeSet 有序
  • ❌ “Map 属于 Collection”——Map 是独立体系
  • ✅ 遍历删除统一用 iterator.remove()removeIf()