* Shared empty array instance used fordefault sized empty instances. We * distinguish this from EMPTY_ELEMENTDATA to know how much to inflate when * first element is added. */ privatestaticfinal Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
/** * Constructs an empty list with an initial capacity of ten. */ publicArrayList(){ // 10个容量的空数组,注意this.elementData一定是指向数组本身 this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; }
1 2 3 4 5 6 7 8 9 10 11 12
publicArrayList(Collection<? extends E> c){ elementData = c.toArray(); //取出集合的数组元素,放到Object[]数组中 if ((size = elementData.length) != 0) { // c.toArray might (incorrectly) not return Object[] (see 6260652) if (elementData.getClass() != Object[].class) // 将c.toArray()拷贝到一个新Object数组上,并用elementData指向它 elementData = Arrays.copyOf(elementData, size, Object[].class); } else { // replace with empty array. this.elementData = EMPTY_ELEMENTDATA; //DEFAULTCAPACITY_EMPTY_ELEMENTDATA用在空参数的构造方法中,而EMPTY_ELEMENTDATA用在入参为集合的构造方法中。 } }
/** * Increases the capacity of this <tt>ArrayList</tt> instance, if * necessary, to ensure that it can hold at least the number of elements * specified by the minimum capacity argument. * * @param minCapacity the desired minimum capacity */ publicvoidensureCapacity(int minCapacity){ int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA) // any size if not default element table ? 0 // larger than default for default empty table. It's already // supposed to be at default size. : DEFAULT_CAPACITY; //上面看的是是否达到10的默认容量,如果计算出的最小需求容量大于最小扩容容量,那么就需要进行扩容了 // 例如minCapacity=11,minExpand要么是0,要么就是10,显然是需要扩容的 if (minCapacity > minExpand) { ensureExplicitCapacity(minCapacity); } }
/** * Trims the capacity of this <tt>ArrayList</tt> instance to be the * list's current size. An application can use this operation to minimize * the storage of an <tt>ArrayList</tt> instance. */ // 官方都说这样裁剪可以使用最小空间来存储一个ArrayList publicvoidtrimToSize(){ modCount++; if (size < elementData.length) { elementData = (size == 0) ? EMPTY_ELEMENTDATA : Arrays.copyOf(elementData, size); } }
publicintindexOf(Object o){ if (o == null) { for (int i = 0; i < size; i++) if (elementData[i]==null) return i; } else { for (int i = 0; i < size; i++) if (o.equals(elementData[i])) return i; } return -1; }
publicintlastIndexOf(Object o){ if (o == null) { for (int i = size-1; i >= 0; i--) if (elementData[i]==null) return i; } else { for (int i = size-1; i >= 0; i--) if (o.equals(elementData[i])) return i; } return -1; }
/** * Returns an array containing all of the elements in this list * in proper sequence (from first to last element). * * <p>The returned array will be "safe" in that no references to it are * maintained by this list. (In other words, this method must allocate * a new array). The caller is thus free to modify the returned array. * * <p>This method acts as bridge between array-based and collection-based * APIs. * * @return an array containing all of the elements in this list in * proper sequence */ public Object[] toArray() { return Arrays.copyOf(elementData, size); }
@SuppressWarnings("unchecked") E elementData(int index){ return (E) elementData[index]; public E get(int index){ rangeCheck(index); return elementData(index); } public E set(int index, E element){ rangeCheck(index); E oldValue = elementData(index); //取出旧值 elementData[index] = element; // 设置新值 return oldValue; //返回旧值 }
rangeCheck
1 2 3 4 5
privatevoidrangeCheck(int index){ //只要给定的下标index大于等于size,即可抛出异常 if (index >= size) thrownew IndexOutOfBoundsException(outOfBoundsMsg(index)); }
add
Shifts the element currently at that position (if any) and any subsequent elements to the right (adds one to their indices).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
publicvoidadd(int index, E element){ rangeCheckForAdd(index); ensureCapacityInternal(size + 1); // Increments modCount!! /* 从源数组的index到index+(length-1)个元素要拷贝,因为length=size - index,因此对于src来说,拷贝的元素范围为[index,index+(size - index -1)],也即src拷贝元素的范围是[index,size-1] 放在目标数组:index+1位置到index+1+(length-1) 而length=size - index个,这里是size是src的实际元素个数,故index+1+(size - index-1)=size 对于dest来说,就是讲src的元素放置在[index+1,size]位置上,由于dest就是源数组,因此需要确保新的源数组容量至少比之前大1个空位。 将[index,size-1]的元素整体往右挪动1格,变成[index+1,size],这就是官方解释的 Shifts the element currently at that position (if any) and any subsequent elements to the right,然后adds one to their indices */ System.arraycopy(elementData, index, elementData, index + 1, size - index); elementData[index] = element; //再将原index位置元素覆盖即可 size++; }
检查所插入的位置index是否合法
1 2 3 4 5 6 7
/** * A version of rangeCheck used by add and addAll. */ privatevoidrangeCheckForAdd(int index){ if (index > size || index < 0) thrownew IndexOutOfBoundsException(outOfBoundsMsg(index)); }
/** * Removes the element at the specified position in this list. * Shifts any subsequent elements to the left (subtracts one from their * indices). * * @param index the index of the element to be removed * @return the element that was removed from the list * @throws IndexOutOfBoundsException {@inheritDoc} */ public E remove(int index){ rangeCheck(index); // 确保给定下标不越界
modCount++; E oldValue = elementData(index); // eturn (E) elementData[index] /*(1) 索引index对齐到size size元素个数的计算视角是从1开始,index索引计算视角是从0开始,先对齐index+1,那么要迁移的元素个数就是 numMoved=size-(index-1) (2)size转为索引视角 size-1就是变成从0开始计数,也即跟索引index对齐 因此计算元素个数:索引a-索引b就是元素差的个数,也即numMoved=size-1-index */ int numMoved = size - index - 1; ; if (numMoved > 0) //从[index+1,size-1]的元素整体向左迁移一格变成[index,size-2] System.arraycopy(elementData, index+1, elementData, index, numMoved); elementData[--size] = null; // clear to let GC do its work 将elementData数组的第size-1个桶位置空用于GC
publicbooleanremove(Object o){ if (o == null) { for (int index = 0; index < size; index++) if (elementData[index] == null) { fastRemove(index); returntrue; } } else { for (int index = 0; index < size; index++) if (o.equals(elementData[index])) { fastRemove(index); returntrue; } } returnfalse; }
fastRemove:其实就是remove方法里面跳过index检查以及目标删除值返回
1 2 3 4 5 6 7 8
privatevoidfastRemove(int index){ modCount++; int numMoved = size - index - 1; if (numMoved > 0) System.arraycopy(elementData, index+1, elementData, index, numMoved); elementData[--size] = null; // clear to let GC do its work }
clear
注意:虽然clear会把所有桶位置null,但是只能算一次结构修改!!
1 2 3 4 5 6 7 8
publicvoidclear(){ modCount++;
// clear to let GC do its work for (int i = 0; i < size; i++) elementData[i] = null; size = 0; // 这里可以再次看到size是实际元素个数 }
System.arraycopy
src: the source array 源数组
srcPoc: 从该位置开始拷贝拷贝元素
dest: 目标数组
destPos:从该位置开始放置拷贝过来元素
length:要将源数组拷贝多少个元素到目标数组中
* @param src . //
* @param srcPos starting position in the source array.
* @param dest the destination array.
* @param destPos starting position in the destination data.
* @param length the number of array elements to be copied.
System.arraycopy(elementData, index, elementData, index + 1,
size - index);
官方注释:
/**
* Copies an array from the specified source array, beginning at the
* specified position, to the specified position of the destination array.
* A subsequence of array components are copied from the source
* array referenced by <code>src</code> to the destination array
* referenced by <code>dest</code>. The number of components copied is
* equal to the <code>length</code> argument. The components at
* positions <code>srcPos</code> through
* <code>srcPos+length-1</code> in the source array are copied into
* positions <code>destPos</code> through
* <code>destPos+length-1</code>, respectively, of the destination
* array.
* <p>
Removes from this list all of the elements whose index is between fromIndex, inclusive, and toIndex, exclusive。Shifts any succeeding elements to the left (reduces their index). This call shortens the list by (toIndex - fromIndex) elements
// clear to let GC do its work // 将size转为索引视角:size-1,将toIndex转为索引视角:toIndex-1,fromIndex本身就是索引视角 // 0->fromIndex->toIndex-1->size-1 //剩余的元素个数为:(size-1)-(toIndex-1-fromIndex)=size-(toIndex-fromIndex) int newSize = size - (toIndex-fromIndex); for (int i = newSize; i < size; i++) { elementData[i] = null; } size = newSize; }
removeAll
1 2 3 4
ArrayList<String> src= new ArrayList<String>(Arrays.asList("foo","bar","foobar","test")); ArrayList<String> dest= new ArrayList<String>(Arrays.asList("foo","bar","foobar")); System.out.println(src.removeAll(dest)); //true System.out.println(src); // [test]
privatebooleanbatchRemove(Collection<?> c, boolean complement){ final Object[] elementData = this.elementData; // 原列表 int r = 0, w = 0; boolean modified = false; // r是读索引指针,w是写索引指针 try { for (; r < size; r++) //size是原列表元素个数 // 首先原列表要删除c这个子集,那么就说要保留只在list且不在c中元素即可 // c.contains(elementData[r])==fasle,说明不在c里面,就将写入到elementData的w位置 // 因此最终就是0到w个保留了,而w+1到size-1被删除 if (c.contains(elementData[r]) == complement) elementData[w++] = elementData[r]; } finally { // Preserve behavioral compatibility with AbstractCollection, // even if c.contains() throws. /* 比如写到第r个元素发生了异常,那么由于elementData保留到[0,w]个元素,那么直接再把r+1到size-1这一段节点迁移到从w开始处 */ if (r != size) { System.arraycopy(elementData, r, elementData, w, size - r); w += size - r; // w是个数,加上拷贝过来的(length= size - r)个就是 } if (w != size) { // clear to let GC do its work for (int i = w; i < size; i++) elementData[i] = null; modCount += size - w; size = w; modified = true; } } return modified; }
retainAll是removeAll的相反版本:
将list保留和c一样的元素,也即只保留c和list的交集
1 2 3 4
public boolean retainAll(Collection<?> c) { Objects.requireNonNull(c); return batchRemove(c, true); }
1 2 3 4
ArrayList<String> src= new ArrayList<String>(Arrays.asList("foo","bar","foobar","test")); ArrayList<String> dest= new ArrayList<String>(Arrays.asList("foo","bar","foobar")); System.out.println(src.retainAll(dest)); System.out.println(src); //[foo, bar, foobar]
// Write out all elements in the proper order. //从遍历的细节可以看出:size是实际的元素个数,因此以下是把实际元素写入流中,所以这里不是用 elementData.length作为遍历极值,因为elementData.length是数组长度容量 for (int i=0; i<size; i++) { s.writeObject(elementData[i]); }
/** * An optimized version of AbstractList.Itr */ privateclassItrimplementsIterator<E> { // 注意以下两个指针都是索引视角 int cursor; // index of next element to return int lastRet = -1; // index of last element returned; -1 if no such int expectedModCount = modCount;
//该方法也是用于处理“剩余需要遍历的元素” @Override @SuppressWarnings("unchecked") publicvoidforEachRemaining(Consumer<? super E> consumer){ Objects.requireNonNull(consumer); finalint size = ArrayList.this.size; //元素个数 int i = cursor; //如果当前游标指针指向size,说明无元素处理了 if (i >= size) { return; } final Object[] elementData = ArrayList.this.elementData; if (i >= elementData.length) { thrownew ConcurrentModificationException(); } // 只要i未越界且迭代过程没有其他结构性修改, while (i != size && modCount == expectedModCount) { //也即consumer.accept((E) elementData[i]),然后在i++ consumer.accept((E) elementData[i++]); } // update once at end of iteration to reduce heap write traffic cursor = i; //循环内部已经更新i指针了,其实此时i=size,cursor=size,lastRet=cursor-1 lastRet = i - 1; checkForComodification(); }
finalvoidcheckForComodification(){ if (modCount != expectedModCount) thrownew ConcurrentModificationException(); } }