本文针对 Java ArrayList
源码中的三个常见疑问展开分析:
1. 减法比较 vs 直接比较
在 grow()
方法中使用 newCapacity - MAX_ARRAY_SIZE > 0
而非直接比较,是为了处理整数溢出的极端情况。
- 直接比较 :若
newCapacity
溢出为负数(如扩容过大),会错误跳过容量校验逻辑。 - 减法比较 :溢出后的结果可能触发
hugeCapacity()
方法,通过检查minCapacity
是否溢出(负数)抛出OutOfMemoryError
,确保异常情况被捕获。
2. MAX_ARRAY_SIZE 设为 Integer.MAX_VALUE - 8 的原因
- 预留元数据空间 :避免因 JVM 对象头(类型指针、数组长度等)占用内存导致分配失败。
- 兼容性保障 :不同 JVM 实现可能对数组元数据有不同要求,预留 8 字节增强通用性。
- 极端突破机制 :
hugeCapacity()
方法仍允许在安全条件下分配至Integer.MAX_VALUE
,平衡安全性与灵活性。
3. modCount 的作用与 Fail-Fast 机制
- 功能 :记录集合结构性修改次数(如增删元素),用于迭代时检测并发修改。
- 实现原理 :迭代器保存初始
expectedModCount
,每次操作前校验与modCount
是否一致,不一致则抛出ConcurrentModificationException
。 - 应用场景 :防止单线程迭代时误改集合,或暴露多线程并发修改问题,辅助开发者快速定位逻辑错误。
核心总结 :通过源码级分析,揭示了 ArrayList
在容量计算、内存分配安全边界及并发修改检测中的设计权衡,体现了 Java 集合框架对稳定性、兼容性和异常处理的细致考量。