Java集合源码阅读应遵循“从用法反推实现”路径:先明确目标(调试/性能/选型/设计模式),再按Iterable→ArrayList/LinkedList→HashMap→AbstractList顺序切入,紧盯elementData、modCount、table等核心字段,边读边用代码验证。

写一份实用的 Java 集合框架源码阅读指南,关键不是堆砌概念,而是帮读者建立可落地的阅读路径和判断依据。核心是“从用法反推实现,再由实现验证行为”,避免一上来就陷进成百上千行代码里。
明确阅读目标:先想清楚你为什么读源码
不同目标决定不同切入点:
- 调试问题(比如
ConcurrentModificationException总在某处抛出)→ 直接定位modCount和expectedModCount的更新与校验逻辑 - 理解性能差异(为什么
ArrayList.get()快、LinkedList.get()慢)→ 聚焦get(int)方法内部是否涉及循环遍历 - 选型决策(该用
HashMap还是TreeMap)→ 对比二者put()的时间复杂度来源:哈希桶寻址 vs 红黑树插入平衡 - 学习设计模式(如迭代器如何解耦遍历与数据结构)→ 重点看
Iterator接口定义 + 各集合的iterator()返回对象实现
推荐阅读顺序:由浅入深,避开早期历史包袱
别从 Vector 或 Hashtable 开始——它们是 Java 1.0 的遗留类,带同步锁、命名不统一,会干扰对现代集合设计的理解。建议按这个节奏推进:
-
第一步:从
Collection和Iterable接口入手 —— 看清“能做什么”(add、remove、iterator()),不关心“怎么做” -
第二步:对比
ArrayList和LinkedList的add()与get()—— 一个用数组索引,一个用双向链表游走,行为差异立刻可见 -
第三步:进入
HashMap的putVal()—— 关注哈希计算、桶位定位、链表转红黑树阈值(TREEIFY_THRESHOLD == 8)、扩容条件(size > threshold) -
第四步:跳到
AbstractList和AbstractSequentialList—— 理解为什么ArrayList继承前者(支持随机访问),而LinkedList继承后者(强调顺序访问)
读源码时必须盯住的几个关键字段和机制
这些是贯穿多数集合类的核心线索,找到它们就抓住了主干:
你接手一个需求时,是不是经常这样:"改一个小字段 → 结果把不相关的代码也改了"、"需求说得很模糊 → 做着做着发现跑偏了"、"数据库加个字段 → 上线才发现漏了数据兼容"、"做了个新功能 → 一个月后自己都忘了当时怎么设计的"、"写到一半被中断 → 再回来不知道从哪继续";这个 Skill 就是专门解决这些问题的。 它会自动探测你的项目环境(JDK、Spring Boot、ORM、数据库、前端框架),记在
立即学习“Java免费学习笔记(深入)”;
-
elementData(ArrayList)、first/last(LinkedList)、table(HashMap)—— 实际存数据的底层容器,先看它是什么类型(数组?Node 链表?Node[] 数组?) -
size—— 当前元素个数,注意它和容量(capacity)不是一回事;ArrayList中它既是长度也是下一个插入位置下标 -
modCount—— 修改计数器,所有非线程安全集合都靠它配合迭代器做快速失败(fail-fast)检查 -
DEFAULT_CAPACITY = 10、MAX_ARRAY_SIZE、LOAD_FACTOR = 0.75f—— 这些常量直接决定扩容时机和内存使用策略 -
transient修饰的字段(如elementData、table)—— 表明它们不参与默认序列化,通常因为内容可重建或含敏感引用
边读边验证:用最小代码印证你的理解
每读一段逻辑,立刻写两行测试代码验证。例如:
读到 ArrayList.grow() 里那句 oldCapacity + (oldCapacity >> 1),马上试:
for (int i = 0; i < 11; i++) list.add("x");
System.out.println(list.size()); // 输出 11
// 再用反射获取 elementData.length,大概率是 15
这种即时反馈能极大提升理解准确度,也避免把注释当实现、把推测当事实。

















