ArrayList是java集合框架中List体系下List接口的一个实现类。
特点:
Resizable(大小可调,尺寸可变)-array (Resizable-array implementation of the <tt>List</tt> interface.This class provides methods to manipulate(巧妙处理) the size of the array that is used internally to store the list.)
所以ArrayList拥有数组元素有序的特点。
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.
Including null (Implements all optional list operations, and permits all elements, including <tt>null</tt>.)
Note that this implementation is not synchronized.
If multiple threads access an <tt>ArrayList</tt> instance concurrently, and at least one of the threads modifies the list structurally, it <i>must</i> be synchronized externally.
If no such object exists, the list should be "wrapped" using the {@link Collections#synchronizedList Collections.synchronizedList} method. This is best done at creation time, to prevent accidental unsynchronized access to the list:
<pre> List list = Collections.synchronizedList(new ArrayList(...));</pre>
方法的时间复杂度
The <tt>size</tt>, <tt>isEmpty</tt>, <tt>get</tt>, <tt>set</tt>,<tt>iterator</tt>, and <tt>listIterator</tt> operations run in constant time(时间复杂度O(1)).
The <tt>add</tt> operation runs in <i>amortized constant time</i>, that is, adding n elements requires O(n) time(时间复杂度 O(n)).
迭代器(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 {@link ListIterator#remove() remove} or
{@link ListIterator#add(Object) add} methods, the iterator will throw a
{@link 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.
如何保证动态扩容
这里主要分析一下,ArrayList#add方法。再说add方法之前,我想说一下另外一件事。当我跟ArrayList源码的时候发现,无论我调用ArrayList哪个带参的构造方法,都会先调用无参构造方法?不知道为什么?也希望能有人帮我解答一下。
来看看add方法源码:
1 /** 2 * Appends the specified element to the end of this list. 3 * 4 * @param e element to be appended to this list 5 * @return <tt>true</tt> (as specified by {@link Collection#add}) 6 */ 7 public boolean add(E e) { 8 ensureCapacityInternal(size + 1); // Increments modCount!! 9 elementData[size++] = e; 10 return true; 11 }
其实add方法就三个步骤:1.确保ArrayList有足够的容量。2将元素添加到集合末尾(elementData是真正存储元素的数组)。3返回。
后面两步都很简单,没有什么好说的。在第一步中又主要分为了如下步骤:
1.方法ensureCapacityInternal(size + 1);
该方法首先确保ArrayList的容量是从10(DEFAULT_CAPACITY==10)起步的。(对于elementData的描述:The array buffer into which the elements of the ArrayList are stored. The capacity of the ArrayList is the length of this array buffer. Any empty ArrayList with elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA will be expanded to DEFAULT_CAPACITY when the first element is added. )
源码:
1 private void ensureCapacityInternal(int minCapacity) { 2 if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { 3 minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity); 4 } 5 6 ensureExplicitCapacity(minCapacity); 7 }
2.ensureExplicitCapacity(int minCapacity)
明确ArrayList容量是否需要扩容,当需要的存储容量大于ArrayList的实际容量时,就需要通过grow(int minCapacity)进行扩容。
源码:
1 private void ensureExplicitCapacity(int minCapacity) { 2 modCount++; 3 4 // overflow-conscious code 5 if (minCapacity - elementData.length > 0) 6 grow(minCapacity); 7 }
3.grow(int minCapacity)
从代码不难看出,通常ArrayList的容量是按照1.5倍进行扩展的。如果1.5倍的容量还不满足最低扩容需要则按照最低扩容需要进行。如果最低扩容大于ArrayList的MAX_ARRAY_SIZE,则将容量扩至最大。
源码:
1 /** 2 * Increases the capacity to ensure that it can hold at least the 3 * number of elements specified by the minimum capacity argument. 4 * 5 * @param minCapacity the desired minimum capacity 6 */ 7 private void grow(int minCapacity) { 8 // overflow-conscious code 9 int oldCapacity = elementData.length; 10 int newCapacity = oldCapacity + (oldCapacity >> 1); 11 if (newCapacity - minCapacity < 0) 12 newCapacity = minCapacity; 13 if (newCapacity - MAX_ARRAY_SIZE > 0) 14 newCapacity = hugeCapacity(minCapacity); 15 // minCapacity is usually close to size, so this is a win: 16 elementData = Arrays.copyOf(elementData, newCapacity); 17 }
4.hugeCapacity(int minCapacity)
源码:
1 private static int hugeCapacity(int minCapacity) { 2 if (minCapacity < 0) // overflow 3 throw new OutOfMemoryError(); 4 return (minCapacity > MAX_ARRAY_SIZE) ? 5 Integer.MAX_VALUE : 6 MAX_ARRAY_SIZE; 7 }
5.Arrays.copyOf(elementData, newCapacity)。扩容
源码:
1 public static <T> T[] copyOf(T[] original, int newLength) { 2 return (T[]) copyOf(original, newLength, original.getClass()); 3 } 4 5 public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) { 6 @SuppressWarnings("unchecked") 7 T[] copy = ((Object)newType == (Object)Object[].class) 8 ? (T[]) new Object[newLength] 9 : (T[]) Array.newInstance(newType.getComponentType(), newLength); 10 System.arraycopy(original, 0, copy, 0, 11 Math.min(original.length, newLength)); 12 return copy; 13 }
ArrayList扩容借助于底层System.arrayCopy方法,该方法属于本地方法。频繁的扩容势必会影响ArrayList的效率。在应用中如果能事先确定ArrayList的大小,那么就按照预知的大小进行初始化,避免初始化的扩容。