ArrayList
描述
List
接口的可调整大小的数组实现。实现所有可选的 List
操作,并允许包括 null
的所有元素。除了实现 List
接口之外,此类还提供一些方法来操纵内部用于存储列表的数组的大小。(此类与Vector
大致等效 ,但它是不同步的。)
size
, isEmpty
, get
, set
, iterator
, 和 listIterator
在 O(1)
时间内运行。add
操作运行摊销恒定时间,添加N元素需要O(n)
的时间。其他操作均以线性时间运行(大致而言)。
每个ArrayList
实例都有一个容量。容量是用于在列表中存储元素的数组的大小。它总是至少与列表大小一样大。随着元素添加到ArrayList中,其容量会自动增长。除了添加元素具有固定的摊销时间成本外,没有指定增长策略的详细信息。
应用程序可以使用ensureCapacity
操作在添加大量元素之前增加ArrayList
实例的容量。这可以减少增量重新分配的数量。
请注意,ArrayList是线程不安全的。 如果多个线程同时访问ArrayList
实例,并且至少有一个线程在做是修改操作,则 必须在外部进行同步。(修改是添加或删除一个或多个元素,或显式调整后备数组的大小的任何操作;仅设置元素的值不是修改。)通常通过在自然封装了对象的某个对象上进行同步来实现。清单。如果不存在这样的对象,则应使用Collections.synchronizedList
方法“包装”列表 。最好在创建时完成此操作,以防止意外的不同步访问列表:
1 | List list = Collections.synchronizedList(new ArrayList(...)); |
此类iterator
和 listIterator
方法返回的迭代器是快速失败的:如果在创建迭代器之后的任何时间对列表进行结构修改,则除了通过迭代器自己的remove
或 add
方法外,迭代器都将抛出 ConcurrentModificationException
。因此,面对并发修改,迭代器将快速而干净地失败,而不是在未来的不确定时间内冒任意,不确定的行为的风险。
注意,迭代器的快速失败行为无法得到保证,因为通常来说,在存在不同步的并发修改的情况下,不可能做出任何严格的保证。快速失败的迭代器会ConcurrentModificationException
尽力而为。因此,编写依赖于此异常的程序的正确性是错误的: 迭代器的快速失败行为应仅用于检测错误。
源码细节
变量
1 | /** 序列化id */ |
构造器
1 | /** |
方法
初始容量为 10
若数组长度小于要扩容的最小值:
默认扩容 1/2
如果还不够就扩容到 最小扩容值
若扩容后的大小超出设置的数组最大容量(Integer.MAX_VALUE - 8)
如果 要扩容的最小值 溢出,抛出异常
如果 要扩容的最小值 小于最大容量值,就使用最大容量值作为扩容后的大小
如果大于,使用
Interger.MAX_VALUE
作为扩容后的大小
trimToSize
1 | /** |
get
1 | /** |
set
1 | /** |
add
1 | /** |
add(int index, E element)
1 | public void add(int index, E element) { |
remove
1 | public E remove(int index) { |
关于 modCount
上面的源码中我们可以看到 modCount++
出现了多次。
源码的doc文档是这样描述的:
modCount
是结构修改的次数(结构修改参考描述中的说明),这个字段用于 iterator
、listIterator
方法所返回的 iterator
实现中:
在 next
、remove
、previous
、set
、add
操作中,如果值得改变不是所预期的,意味着多个线程同时修改了 List,这样就会抛出异常:ConcurrentModificationException
。这也是所说的快速失败机制。