JDK8 ArrayList源码分析

388 阅读5分钟

1. ArrayList类注释翻译

Resizable-array implementation of the List interface. Implements all optional list operations, and permits all elements, including null. In addition to implementing the List interface, this class provides methods to manipulate the size of the array that is used internally to store the list. (This class is roughly equivalent to Vector, except that it is unsynchronized.) ArrayList是List接口的可变数组实现。ArrayList实现了所有可选的list操作,并且允许所有元素,包括null。ArrayList除了实现List接口以外,这个类还提供了操控数组(数组在内部被用来存储list)大小的方法。(ArrayList大体上等同于Vector,除了ArrayList是非线程安全的。)

The size, isEmpty, get, set, iterator, and listIterator operations run in constant time. The add operation runs in amortized constant time, that is, adding n elements requires O(n) time. All of the other operations run in linear time (roughly speaking). The constant factor is low compared to that for the LinkedList implementation. 执行size、isEmpty、get、set、iterator以及listIterator操作需要常数时间。执行add操作需要分摊后的常数时间,也就是说,添加n个元素所需要的时间复杂度是O(n)。执行其他所有操作需要线性的时间(大体来说)。 和LinkedList比较这个常数因子是较低的。

Each ArrayList instance has a capacity. The capacity is the size of the array used to store the elements in the list. It is always at least as large as the list size. As elements are added to an ArrayList, its capacity grows automatically. The details of the growth policy are not specified beyond the fact that adding an element has constant amortized time cost. 每个ArrayList实例都有一个容量。这个容量是被用来存储list中元素的数组的大小。这个容量至少和list的大小一样大。当元素被添加到ArrayList中时,ArrayList自动扩容。除了添加一个元素花费分摊后的常数时间外,增长策略的细节没有被指定。

An application can increase the capacity of an ArrayList instance before adding a large number of elements using the ensureCapacity operation. This may reduce the amount of incremental reallocation. 一个应用可以在添加大量元素之前使用ensureCapacity操作提高一个ArrayList实例的容量。这会减少递增的再分配次数。

Note that this implementation is not synchronized. If multiple threads access an ArrayList instance concurrently, and at least one of the threads modifies the list structurally, it must be synchronized externally. (A structural modification is any operation that adds or deletes one or more elements, or explicitly resizes the backing array; merely setting the value of an element is not a structural modification.) This is typically accomplished by synchronizing on some object that naturally encapsulates the list. If no such object exists, the list should be "wrapped" using the Collections.synchronizedList method. This is best done at creation time, to prevent accidental unsynchronized access to the list: 注意:这个实现是非线程安全的。如果多个线程同时访问一个ArrayList实例,并且至少一个线程在结构上修改这个list,它必须在外部被同步。(结构性的修改是指任何添加或删除一个或多个元素、调整内部数组大小;仅仅只是设置一个元素的值不是一个结构性的修改。)这通常是通过同步某一对象自然地封装这个list来实现的。如果没有这样的对象存在,这个list应当被用Collections.synchronizedList方法来包装。为了预防意外的非同步访问这个list,这最好在创建时进行: List list = Collections.synchronizedList(new ArrayList(...));

The iterators returned by this class's iterator and listIterator methods are fail-fast: if the list is structurally modified at any time after the iterator is created, in any way except through the iterator's own remove or add methods, the iterator will throw a ConcurrentModificationException. Thus, in the face of concurrent modification, the iterator fails quickly and cleanly, rather than risking arbitrary, non-deterministic behavior at an undetermined time in the future. 这个类的iterator方法和listIterator方法返回的迭代器是fail-fast的:如果在迭代器被创建后这个list被在结构上改变了,除非是通过迭代器自身的remove或者add方法,这个迭代器将会抛出ConcurrentModificationException。因此,面对并发修改,这个迭代器迅速干脆地失败,而不是冒着在未来某个不确定地时间出现任意不确定地行为地风险。

Note that the fail-fast behavior of an iterator cannot be guaranteed as it is, generally speaking, impossible to make any hard guarantees in the presence of unsynchronized concurrent modification. Fail-fast iterators throw ConcurrentModificationException on a best-effort basis. Therefore, it would be wrong to write a program that depended on this exception for its correctness: the fail-fast behavior of iterators should be used only to detect bugs. 注意:事实上一个迭代器的fail-fast行为不能够被保证,通常来说,当出现非同步的并发修改时不可能作出任何严格的保证。Fail-fast迭代器尽最大努力抛出ConcurrentModificationException。因此,写一个基于这个异常的正确性的程序是错误的:fail-fast行为应当只是被用来定位问题。

2. elementData不会被序列化

transient Object[] elementData;

从变量声明情况来看,如果序列化ArrayList实例,elementData存储的数据是不会保存下来的,实际开发中后端暴露的api返回的对象中常常包含ArrayList,这个数据是怎么传递的?具体情况待验证。

3. 内部数组elementData扩容

private static final int DEFAULT_CAPACITY = 10;

默认容量是10。

private void grow(int minCapacity) {
    // overflow-conscious code
    int oldCapacity = elementData.length;
    int newCapacity = oldCapacity + (oldCapacity >> 1);
    if (newCapacity - minCapacity < 0)
        newCapacity = minCapacity;
    if (newCapacity - MAX_ARRAY_SIZE > 0)
        newCapacity = hugeCapacity(minCapacity);
    // minCapacity is usually close to size, so this is a win:
    elementData = Arrays.copyOf(elementData, newCapacity);
}

自动扩容后容量是原容量的1.5倍。

指定扩容也会先检测自动扩容是否满足,不满足再按照指定容量扩容。

类注释上提到的ensureCapacity方法最终也是调用的这个grow方法。当然,会先作扩容必要性的判断。

public void ensureCapacity(int minCapacity);

4. subList方法

调用subList方法返回私有内部类SubList的实例,只是索引了原ArrayList实例的部分内容。没有提供add、remove等修改内部数组结构的操作。使用时要慎重。

具体可以参考juejin.cn/post/696606…