OpenJDK 源码阅读之 ArrayList
概要
- 类继承关系
|
|
- 定义
|
|
实现
- transient
|
|
声明为 transient
后,这个字段不会被序列化。
- toArray
|
|
注意对 elementData
的检查,Bug 6260652中对此有详细描述。主要原因是 c.toArray()
不一定会返回 Object[]
类型的值。
- SuppressWarnings
|
|
告诉编译器,对特定类型的 warning
保持静默。
- 参数检查
可以看出标准库中的程序,在很多地方都需要对参数进行检查,以保证程序的健壮性。
检查 null
|
|
检查参数上界,下界
|
|
- ArrayList 的 index 检查
|
|
|
|
|
|
注意 rangeCheck
只检查了上界,但是如果将 index
设置成负数,也会抛出异常,异常是在 elementData[index]
中抛出的,猜想是在数组的实现中,对负数进行检查,因为任何一个数组,index
都不可能为负数,但是在实现数组时,不知道数组的元素个数,所以上界检查在此时发生。
- 元素访问
|
|
专门写了一个函数用来访问元素,而不是直接使用 elementData[index]
,只因为需要向上转型么?还是 SuppressWarning
会重复。
- private
对于仅仅在类内部使用的函数,要声明为 private
。
- add 参数检查
|
|
|
|
可以看出这里对 index
的上界和下界都检查了,虽然 add
的7
行会进行检查,但在 add
的 4
, 5
行中就已经可能出错。
- 强制垃圾回收
|
|
注意第 11
行把最后一个元素设置为null
,这可以使得gc
工作。好奇如何用实验验证这一点。
- remove(Object o)
|
|
整个框架与 indexOf
函数是相似的,注意那个 fastRemove
函数,它与 remove(index)
的不同在于它:
- 是
private
- 无参数检查,因为传给它的参数一定是合法的
- 不返回值
由此细节可见,标准库中函数的精益求精。(不知道是不是我过度揣测了,有经过性能测试么?)
- batchRemove
|
|
注意 finally
里的代码,这段代码保证,即使 try
中的代码出了问题,也会最大程度上保证数据的一致性。如果 r
没有遍历完,那么后面没有检查过的数据都要保留下来。
- 线程安全
|
|
注意那个 modCount
的检查,这是为了确定在 5-12
行代码执行过程中,List
没有改变。改变的原因可能是由于多线程并发执行,在这期间另一个线程执行,改变了 List
的状态。
- 容量扩充
容量扩充会在任何可能引起 ArrayList
大小改变的情况下发生,如何扩充呢,代码在 grow
函数中。
|
|
可以看出,oldCapacity
新增的容量是它的一半。另外,还有一个 hugeCapacity
,如果需要扩充的容量比 MAX_ARRAY_SIZE
还大,会调用这个函数,重新调整大小。但再大也大不过 Integer.MAX_VALUE
。
- 元素位置调整
|
|
无论是增加元素还是删除元素,都可能使得很多元素的位置发生改变,这里就是用 System.arraycopy
来把大量元素放在其它位置,如果元素很多,经常需要调整,是很浪费时间的。