JAva ArrayListソースコード解析

26692 ワード



public class ArrayList<E> extends AbstractList<E> implements List<E>,
	RandomAccess, Cloneable, java.io.Serializable {
    private static final long serialVersionUID = 8683452581122892189L;

    /**
     * Default initial capacity.     
     */
    private static final int DEFAULT_CAPACITY = 10;

    /**
     * Shared empty array instance used for empty instances.
     */
    private static final Object[] EMPTY_ELEMENTDATA = {};

    /**
     *           transient:            
     */
    private transient Object[] elementData;

    /**
     * arrayList   
     */
    private int size;

    /**
     * 
     */
    public ArrayList(int initialCapacity) {
	super();
	if (initialCapacity < 0)
	    throw new IllegalArgumentException("Illegal Capacity: "
		    + initialCapacity);
	this.elementData = new Object[initialCapacity];
    }

    /**
     * Constructs an empty list with an initial capacity of ten.
     */
    public ArrayList() {
	super();
	this.elementData = EMPTY_ELEMENTDATA;
    }

    /**
     * 
     */
    public ArrayList(Collection<? extends E> c) {
	elementData = c.toArray();
	size = elementData.length;
	//   elementData      Object[] ,    Object[]
	if (elementData.getClass() != Object[].class)
	    elementData = Arrays.copyOf(elementData, size, Object[].class);
    }

    /**
     * ArrayList    array[]     2      ,   oldLength = oldLength + oldLength*2;
     *            ,                ,      
     */
    public void trimToSize() {
	modCount++;
	if (size < elementData.length) {
	    elementData = Arrays.copyOf(elementData, size);
	}
    }

    /**
     * 
     */
    public void ensureCapacity(int minCapacity) {
	int minExpand = (elementData != EMPTY_ELEMENTDATA)
	// any size if real element table
	? 0
		// larger than default for empty table. It's already supposed to
		// be
		// at default size.
		: DEFAULT_CAPACITY;

	if (minCapacity > minExpand) {
	    ensureExplicitCapacity(minCapacity);
	}
    }

    private void ensureCapacityInternal(int minCapacity) {
	if (elementData == EMPTY_ELEMENTDATA) {
	    minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
	}

	ensureExplicitCapacity(minCapacity);
    }

    private void ensureExplicitCapacity(int minCapacity) {
	modCount++;

	// overflow-conscious code
	if (minCapacity - elementData.length > 0)
	    grow(minCapacity);
    }

    /**
     *       
     */
    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

    /**
     *    ArrayList  array ,  ArrayList
     */
    private void grow(int minCapacity) {
	// overflow-conscious code
	int oldCapacity = elementData.length;
	int newCapacity = oldCapacity + (oldCapacity >> 1);//   2 
	if (newCapacity - minCapacity < 0)//   2             ,
	    newCapacity = minCapacity;//         ,       newCapacity
	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);
    }

    /**
     *  array     
     * 
     * @param minCapacity
     * @return
     */
    private static int hugeCapacity(int minCapacity) {
	//        
	if (minCapacity < 0) // overflow
	    throw new OutOfMemoryError();
	return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE
		: MAX_ARRAY_SIZE;
    }

    /**
     *   arraylist           
     */
    public int size() {
	return size;
    }

    /**
     *   ArrayList    ,           0
     */
    public boolean isEmpty() {
	return size == 0;
    }

    /**
     * ArrayList         ,   indexOf() indexOf(o) >= 0      
     */
    public boolean contains(Object o) {
	return indexOf(o) >= 0;
    }

    /**
     *      ArrayList        ,     -1
     */
    public int indexOf(Object o) {
	if (o == null) {// null     
	    for (int i = 0; i < size; i++)
		if (elementData[i] == null)
		    return i;
	} else { //  null equals        
	    for (int i = 0; i < size; i++)
		if (o.equals(elementData[i]))
		    return i;
	}
	return -1;
    }

    /**
     *   ,       ArrayList   ,     -1
     */
    public int lastIndexOf(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;
    }

    /**
     *   arrayList  
     */
    public Object clone() {
	try {
	    @SuppressWarnings("unchecked")
	    ArrayList<E> v = (ArrayList<E>) super.clone();
	    v.elementData = Arrays.copyOf(elementData, size);
	    v.modCount = 0;
	    return v;
	} catch (CloneNotSupportedException e) {
	    // this shouldn't happen, since we are Cloneable
	    throw new InternalError();
	}
    }

    /**
     *   arrayList     ,      ,     ArrayList     
     */
    public Object[] toArray() {
	return Arrays.copyOf(elementData, size);
    }

    /**
     * arrayList         
     */
    @SuppressWarnings("unchecked")
    public <T> T[] toArray(T[] a) {
	if (a.length < size)//              arrayList   ,  arrayList
	    // Make a new array of a's runtime type, but my contents:
	    return (T[]) Arrays.copyOf(elementData, size, a.getClass());
	System.arraycopy(elementData, 0, a, 0, size);
	if (a.length > size)//
	    a[size] = null;//             
	return a;
    }

    // Positional Access Operations

    @SuppressWarnings("unchecked")
    E elementData(int index) {
	return (E) elementData[index];
    }

    /**
     *  arrayList       
     */
    public E get(int index) {
	rangeCheck(index);//      ,         

	return elementData(index);
    }

    /**
     * arrayList     ,     
     */
    public E set(int index, E element) {
	rangeCheck(index);//      ,         

	E oldValue = elementData(index);
	elementData[index] = element;
	return oldValue;
    }

    /**
     * arrayList       
     */
    public boolean add(E e) {
	ensureCapacityInternal(size + 1); //          array  
	elementData[size++] = e;
	return true;
    }

    /**
     * 
     */
    public void add(int index, E element) {
	rangeCheckForAdd(index);

	ensureCapacityInternal(size + 1); // Increments modCount!!
	System.arraycopy(elementData, index, elementData, index + 1, size
		- index);
	elementData[index] = element;
	size++;
    }

    /**
     *   index   ,index       
     */
    public E remove(int index) {
	rangeCheck(index);

	modCount++;
	E oldValue = elementData(index);

	int numMoved = size - index - 1;
	if (numMoved > 0)
	    System.arraycopy(elementData, index + 1, elementData, index,
		    numMoved);
	elementData[--size] = null; //      ,               ,array        ,          

	return oldValue;
    }

    /**
     * 
     */
    public boolean remove(Object o) {
	if (o == null) {
	    for (int index = 0; index < size; index++)
		if (elementData[index] == null) {
		    fastRemove(index);
		    return true;
		}
	} else {
	    for (int index = 0; index < size; index++)
		if (o.equals(elementData[index])) {
		    fastRemove(index);
		    return true;
		}
	}
	return false;
    }

    /*
     * Private remove method that skips bounds checking and does not return the
     * value removed.
     */
    private void fastRemove(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
    }

    /**
     * 
     */
    public void clear() {
	modCount++;

	// clear to let GC do its work
	for (int i = 0; i < size; i++)
	    elementData[i] = null;

	size = 0;
    }

    /**
     * 
     */
    public boolean addAll(Collection<? extends E> c) {
	Object[] a = c.toArray();
	int numNew = a.length;
	ensureCapacityInternal(size + numNew); // Increments modCount
	System.arraycopy(a, 0, elementData, size, numNew);
	size += numNew;
	return numNew != 0;
    }

    /**
     * 
     */
    public boolean addAll(int index, Collection<? extends E> c) {
	rangeCheckForAdd(index);

	Object[] a = c.toArray();
	int numNew = a.length;
	ensureCapacityInternal(size + numNew); // Increments modCount

	int numMoved = size - index;
	if (numMoved > 0)
	    System.arraycopy(elementData, index, elementData, index + numNew,
		    numMoved);

	System.arraycopy(a, 0, elementData, index, numNew);
	size += numNew;
	return numNew != 0;
    }

    /**
     * 
     */
    protected void removeRange(int fromIndex, int toIndex) {
	modCount++;
	int numMoved = size - toIndex;
	System.arraycopy(elementData, toIndex, elementData, fromIndex, numMoved);

	// clear to let GC do its work
	int newSize = size - (toIndex - fromIndex);
	for (int i = newSize; i < size; i++) {
	    elementData[i] = null;
	}
	size = newSize;
    }

    private void rangeCheck(int index) {
	if (index >= size)
	    throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    }

    /**
     * A version of rangeCheck used by add and addAll.
     */
    private void rangeCheckForAdd(int index) {
	if (index > size || index < 0)
	    throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    }

    private String outOfBoundsMsg(int index) {
	return "Index: " + index + ", Size: " + size;
    }

    /**
     *   ArrayList   c   
     */
    public boolean removeAll(Collection<?> c) {
	return batchRemove(c, false);
    }

    /**
     * c        
     */
    public boolean retainAll(Collection<?> c) {
	return batchRemove(c, true);
    }

    /**
     * removeAll retainAll     complement     c          c  
     */
    private boolean batchRemove(Collection<?> c, boolean complement) {
	final Object[] elementData = this.elementData;
	int r = 0, w = 0;
	boolean modified = false;
	try {
	    for (; r < size; r++)
		if (c.contains(elementData[r]) == complement)// complement=false
		    elementData[w++] = elementData[r];//  c            
	} finally {
	    // Preserve behavioral compatibility with AbstractCollection,
	    // even if c.contains() throws.
	    if (r != size) {//      r==size,             ,              
		System.arraycopy(elementData, r, elementData, w, size - r);
		w += size - r;// w               
	    }
	    if (w != size) {// 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;
    }

    /**
     * Save the state of the <tt>ArrayList</tt> instance to a stream (that is,
     * serialize it).
     * 
     * @serialData The length of the array backing the <tt>ArrayList</tt>
     *             instance is emitted (int), followed by all of its elements
     *             (each an <tt>Object</tt>) in the proper order.
     */
    private void writeObject(java.io.ObjectOutputStream s)
	    throws java.io.IOException {
	// Write out element count, and any hidden stuff
	int expectedModCount = modCount;
	s.defaultWriteObject();

	// Write out size as capacity for behavioural compatibility with clone()
	s.writeInt(size);

	// Write out all elements in the proper order.
	for (int i = 0; i < size; i++) {
	    s.writeObject(elementData[i]);
	}

	if (modCount != expectedModCount) {
	    throw new ConcurrentModificationException();
	}
    }

    /**
     * Reconstitute the <tt>ArrayList</tt> instance from a stream (that is,
     * deserialize it).
     */
    private void readObject(java.io.ObjectInputStream s)
	    throws java.io.IOException, ClassNotFoundException {
	elementData = EMPTY_ELEMENTDATA;

	// Read in size, and any hidden stuff
	s.defaultReadObject();

	// Read in capacity
	s.readInt(); // ignored

	if (size > 0) {
	    // be like clone(), allocate array based upon size not capacity
	    ensureCapacityInternal(size);

	    Object[] a = elementData;
	    // Read in all elements in the proper order.
	    for (int i = 0; i < size; i++) {
		a[i] = s.readObject();
	    }
	}
    }

    /**
     * Returns a list iterator over the elements in this list (in proper
     * sequence), starting at the specified position in the list. The specified
     * index indicates the first element that would be returned by an initial
     * call to {@link ListIterator#next next}. An initial call to
     * {@link ListIterator#previous previous} would return the element with the
     * specified index minus one.
     * 
     * <p>
     * The returned list iterator is <a href="#fail-fast"><i>fail-fast</i></a>.
     * 
     * @throws IndexOutOfBoundsException
     *             {@inheritDoc}
     */
    public ListIterator<E> listIterator(int index) {
	if (index < 0 || index > size)
	    throw new IndexOutOfBoundsException("Index: " + index);
	return new ListItr(index);
    }

    /**
     * Returns a list iterator over the elements in this list (in proper
     * sequence).
     * 
     * <p>
     * The returned list iterator is <a href="#fail-fast"><i>fail-fast</i></a>.
     * 
     * @see #listIterator(int)
     */
    public ListIterator<E> listIterator() {
	return new ListItr(0);
    }

    /**
     * Returns an iterator over the elements in this list in proper sequence.
     * 
     * <p>
     * The returned iterator is <a href="#fail-fast"><i>fail-fast</i></a>.
     * 
     * @return an iterator over the elements in this list in proper sequence
     */
    public Iterator<E> iterator() {
	return new Itr();
    }

    /**
     * An optimized version of AbstractList.Itr
     */
    private class Itr implements Iterator<E> {
	int cursor; // index of next element to return
	int lastRet = -1; // index of last element returned; -1 if no such
	int expectedModCount = modCount;

	public boolean hasNext() {
	    return cursor != size;
	}

	@SuppressWarnings("unchecked")
	public E next() {
	    checkForComodification();
	    int i = cursor;
	    if (i >= size)
		throw new NoSuchElementException();
	    Object[] elementData = ArrayList.this.elementData;
	    if (i >= elementData.length)
		throw new ConcurrentModificationException();
	    cursor = i + 1;
	    return (E) elementData[lastRet = i];
	}

	public void remove() {
	    if (lastRet < 0)
		throw new IllegalStateException();
	    checkForComodification();

	    try {
		ArrayList.this.remove(lastRet);
		cursor = lastRet;
		lastRet = -1;
		expectedModCount = modCount;
	    } catch (IndexOutOfBoundsException ex) {
		throw new ConcurrentModificationException();
	    }
	}

	final void checkForComodification() {
	    if (modCount != expectedModCount)
		throw new ConcurrentModificationException();
	}
    }

    /**
     * An optimized version of AbstractList.ListItr
     */
    private class ListItr extends Itr implements ListIterator<E> {
	ListItr(int index) {
	    super();
	    cursor = index;
	}

	public boolean hasPrevious() {
	    return cursor != 0;
	}

	public int nextIndex() {
	    return cursor;
	}

	public int previousIndex() {
	    return cursor - 1;
	}

	@SuppressWarnings("unchecked")
	public E previous() {
	    checkForComodification();
	    int i = cursor - 1;
	    if (i < 0)
		throw new NoSuchElementException();
	    Object[] elementData = ArrayList.this.elementData;
	    if (i >= elementData.length)
		throw new ConcurrentModificationException();
	    cursor = i;
	    return (E) elementData[lastRet = i];
	}

	public void set(E e) {
	    if (lastRet < 0)
		throw new IllegalStateException();
	    checkForComodification();

	    try {
		ArrayList.this.set(lastRet, e);
	    } catch (IndexOutOfBoundsException ex) {
		throw new ConcurrentModificationException();
	    }
	}

	public void add(E e) {
	    checkForComodification();

	    try {
		int i = cursor;
		ArrayList.this.add(i, e);
		cursor = i + 1;
		lastRet = -1;
		expectedModCount = modCount;
	    } catch (IndexOutOfBoundsException ex) {
		throw new ConcurrentModificationException();
	    }
	}
    }

    /**
     *    arrayList subarrayList, subarrayList      arrayList    ,              
     */
    public List<E> subList(int fromIndex, int toIndex) {
	subListRangeCheck(fromIndex, toIndex, size);//       
	return new SubList(this, 0, fromIndex, toIndex);
    }

    static void subListRangeCheck(int fromIndex, int toIndex, int size) {
	if (fromIndex < 0)
	    throw new IndexOutOfBoundsException("fromIndex = " + fromIndex);
	if (toIndex > size)
	    throw new IndexOutOfBoundsException("toIndex = " + toIndex);
	if (fromIndex > toIndex)
	    throw new IllegalArgumentException("fromIndex(" + fromIndex
		    + ") > toIndex(" + toIndex + ")");
    }

    private class SubList extends AbstractList<E> implements RandomAccess {
	private final AbstractList<E> parent;
	private final int parentOffset;// subArrayList
				       //          ,   arrayList            
	private final int offset;
	int size;

	SubList(AbstractList<E> parent, int offset, int fromIndex, int toIndex) {
	    this.parent = parent;
	    this.parentOffset = fromIndex;
	    this.offset = offset + fromIndex;
	    this.size = toIndex - fromIndex;
	    this.modCount = ArrayList.this.modCount;
	}

	public E set(int index, E e) {
	    rangeCheck(index);
	    checkForComodification();
	    E oldValue = ArrayList.this.elementData(offset + index);
	    ArrayList.this.elementData[offset + index] = e;
	    return oldValue;
	}

	public E get(int index) {
	    rangeCheck(index);
	    checkForComodification();
	    return ArrayList.this.elementData(offset + index);
	}

	public int size() {
	    checkForComodification();
	    return this.size;
	}

	public void add(int index, E e) {
	    rangeCheckForAdd(index);
	    checkForComodification();
	    parent.add(parentOffset + index, e);
	    this.modCount = parent.modCount;
	    this.size++;
	}

	public E remove(int index) {
	    rangeCheck(index);
	    checkForComodification();
	    E result = parent.remove(parentOffset + index);
	    this.modCount = parent.modCount;
	    this.size--;
	    return result;
	}

	protected void removeRange(int fromIndex, int toIndex) {
	    checkForComodification();
	    parent.removeRange(parentOffset + fromIndex, parentOffset + toIndex);
	    this.modCount = parent.modCount;
	    this.size -= toIndex - fromIndex;
	}

	public boolean addAll(Collection<? extends E> c) {
	    return addAll(this.size, c);
	}

	public boolean addAll(int index, Collection<? extends E> c) {
	    rangeCheckForAdd(index);
	    int cSize = c.size();
	    if (cSize == 0)
		return false;

	    checkForComodification();
	    parent.addAll(parentOffset + index, c);
	    this.modCount = parent.modCount;
	    this.size += cSize;
	    return true;
	}

	public Iterator<E> iterator() {
	    return listIterator();
	}

	public ListIterator<E> listIterator(final int index) {
	    checkForComodification();
	    rangeCheckForAdd(index);
	    final int offset = this.offset;

	    return new ListIterator<E>() {
		int cursor = index;
		int lastRet = -1;
		int expectedModCount = ArrayList.this.modCount;

		public boolean hasNext() {
		    return cursor != SubList.this.size;
		}

		@SuppressWarnings("unchecked")
		public E next() {
		    checkForComodification();
		    int i = cursor;
		    if (i >= SubList.this.size)
			throw new NoSuchElementException();
		    Object[] elementData = ArrayList.this.elementData;
		    if (offset + i >= elementData.length)
			throw new ConcurrentModificationException();
		    cursor = i + 1;
		    return (E) elementData[offset + (lastRet = i)];
		}

		public boolean hasPrevious() {
		    return cursor != 0;
		}

		@SuppressWarnings("unchecked")
		public E previous() {
		    checkForComodification();
		    int i = cursor - 1;
		    if (i < 0)
			throw new NoSuchElementException();
		    Object[] elementData = ArrayList.this.elementData;
		    if (offset + i >= elementData.length)
			throw new ConcurrentModificationException();
		    cursor = i;
		    return (E) elementData[offset + (lastRet = i)];
		}

		public int nextIndex() {
		    return cursor;
		}

		public int previousIndex() {
		    return cursor - 1;
		}

		public void remove() {
		    if (lastRet < 0)
			throw new IllegalStateException();
		    checkForComodification();

		    try {
			SubList.this.remove(lastRet);
			cursor = lastRet;
			lastRet = -1;
			expectedModCount = ArrayList.this.modCount;
		    } catch (IndexOutOfBoundsException ex) {
			throw new ConcurrentModificationException();
		    }
		}

		public void set(E e) {
		    if (lastRet < 0)
			throw new IllegalStateException();
		    checkForComodification();

		    try {
			ArrayList.this.set(offset + lastRet, e);
		    } catch (IndexOutOfBoundsException ex) {
			throw new ConcurrentModificationException();
		    }
		}

		public void add(E e) {
		    checkForComodification();

		    try {
			int i = cursor;
			SubList.this.add(i, e);
			cursor = i + 1;
			lastRet = -1;
			expectedModCount = ArrayList.this.modCount;
		    } catch (IndexOutOfBoundsException ex) {
			throw new ConcurrentModificationException();
		    }
		}

		final void checkForComodification() {
		    if (expectedModCount != ArrayList.this.modCount)
			throw new ConcurrentModificationException();
		}
	    };
	}

	public List<E> subList(int fromIndex, int toIndex) {
	    subListRangeCheck(fromIndex, toIndex, size);
	    return new SubList(this, offset, fromIndex, toIndex);
	}

	private void rangeCheck(int index) {
	    if (index < 0 || index >= this.size)
		throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
	}

	private void rangeCheckForAdd(int index) {
	    if (index < 0 || index > this.size)
		throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
	}

	private String outOfBoundsMsg(int index) {
	    return "Index: " + index + ", Size: " + this.size;
	}

	private void checkForComodification() {
	    if (ArrayList.this.modCount != this.modCount)
		throw new ConcurrentModificationException();
	}
    }
}