JAVA 集合类(java.util)源码阅读笔记------ArrayList

Posted Itzel_yuki

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JAVA 集合类(java.util)源码阅读笔记------ArrayList相关的知识,希望对你有一定的参考价值。

一、继承关系

public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable

继承自AbstractList抽象类,实现List接口,RandomAccess接口,Cloneable接口, java.io.Serializable接口。

说明:
(1)RandomAccess:空接口,实现该接口代表该类拥有随机访问list对象的能力。
(2)Cloneable:空接口,实现该接口,重写Object的clone方法,否则会抛出异常。调用super.clone()实现对象的复制,如果对象中有引用,可以在super.clone后面进行处理。
(3)java.io.Serializable:空接口,实现该接口代表该类可序列化

类中的方法都是对List接口中方法的具体实现。

二、成员变量

private static final int DEFAULT_CAPACITY = 10;//默认的数组长度
transient Object[] elementData;//存储list中元素的数组,transient关键字表示该对象在ArrayList序列化时不被序列化。
private int size;//数组中实际元素的个数
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;//数组的最大长度

三、重要方法说明

(1)clone: 保证复制ArrayList对象时,内部包含的elementData数组引用能重新申请空间创建数组,为深复制。
    public Object clone() 
        try 
            ArrayList<?> v = (ArrayList<?>) super.clone();
			//保证该clone是深复制,不加这句话,则复制的ArrayList对象中elementData指向的还是原对象中的数组。
            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(e);
        
    


(2)toArray:传入参数,将elementData中数据存入的数组。若该数组的长度<size,则重新返回一个复制了elementData数据的该类型数组;否则直接将elementData中元素向a中复制,同时将a[size()]置为空,返回a。
@SuppressWarnings("unchecked")
    public <T> T[] toArray(T[] a) 
        if (a.length < size)
            // 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;
    


(3)add:当数组长度不够时,需要动态扩容
    public boolean add(E e) 
        ensureCapacityInternal(size + 1);  // size为element数组的实际大小,若size+1<elementData.length,则不用动态扩容,否则需要将elementData进行动态扩容。
        elementData[size++] = e;
        return true;
    
	private void ensureCapacityInternal(int minCapacity) 
        if (elementData == DEFAULTCAPACITY_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);
    
	grow:elementData数组扩容
	private void grow(int minCapacity) 
        // overflow-conscious code
        int oldCapacity = elementData.length;
		//每次增长newCapacity=oldCapacity*1.5,为原来的1.5倍
        int newCapacity = oldCapacity + (oldCapacity >> 1);
		//如果oldCapacity*1.5倍后,容量还是比minCapacity要小,则将newCapacity的值直接置为minCapacity
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
		//如果增长的新长度大于了MAX_ARRAY_SIZE,则调用hugeCapacity来获取一个不大于Integer.MAX_VALUE的值。
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        // minCapacity is usually close to size, so this is a win:
		//重新申请一个newCapacity长度的数组空间,并把elementData数组中内容拷贝过去。
        elementData = Arrays.copyOf(elementData, newCapacity);
    
	hugeCapacity: elementData的最大容量
	private static int hugeCapacity(int minCapacity) 
        if (minCapacity < 0) // overflow
            throw new OutOfMemoryError();
		//当最小保证的容量minCapacity比MAX_ARRAY_SIZE还大时,返回Integer.MAX_VALUE;否则直接返回MAX_ARRAY_SIZE
        return (minCapacity > MAX_ARRAY_SIZE) ?
            Integer.MAX_VALUE :
            MAX_ARRAY_SIZE;
    


(4) add:在指定位置add一个元素
    public void add(int index, E element) 
        rangeCheckForAdd(index);

        ensureCapacityInternal(size + 1);  // 确保数组的长度>=size+1
		//将elementData中index到数组最后一个元素,整体向后移动一个位置,空出index这一个位置,将element填入
        System.arraycopy(elementData, index, elementData, index + 1,
                         size - index);
        elementData[index] = element;
        size++;
    
	 public boolean addAll(int index, Collection<? extends E> c) 
        rangeCheckForAdd(index);

        Object[] a = c.toArray();
        int numNew = a.length;
		//确保数组能容下添加的所有元素,可能进行动态扩容
        ensureCapacityInternal(size + numNew);  // Increments modCount

		//计算从Index到处数组最后一个元素需要移动的元素的个数
        int numMoved = size - index;
        if (numMoved > 0)
		//直接采用System.arraycopy将elementData数组中从index开始到最后一个元素位置这一段数据,移动到index+numNew位置
            System.arraycopy(elementData, index, elementData, index + numNew,
                             numMoved);
		//若index等于size,则直接在原数组后面添加
        System.arraycopy(a, 0, elementData, index, numNew);
        size += numNew;
        return numNew != 0;
    


(5)remove
	//是一个前闭后开的区间,就是toIndex位置的元素不被移除,fromIndex位置元素被移除
	protected void removeRange(int fromIndex, int toIndex) 
        modCount++;
		//需要移动的元素的个数=toIndex到最后一个元素位置
        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;//设置为null,让gc有机会回收
        
        size = newSize;
    



(6)此外还提供了private void readObject(java.io.ObjectInputStream s)、 private void writeObject(java.io.ObjectOutputStream s)两个私有的序列化反序列化方法。


注意:
关于ArrayList中的Iterable(collection继承自此接口,所以collection的所有子类或者实现类都需要实现Iterator方法)接口中iterator()方法的实现
若一个线程在操作该ArrayList的iterator时,另一个线程对该ArrayList对象进行了添加修改删除更新操作,则会抛出new ConcurrentModificationException();
原因:http://www.cnblogs.com/skywang12345/p/3308762.html



以上是关于JAVA 集合类(java.util)源码阅读笔记------ArrayList的主要内容,如果未能解决你的问题,请参考以下文章

JAVA 集合类(java.util)源码阅读笔记------ArrayList

JAVA 集合类(java.util)源码阅读笔记------Hashtable

JAVA 集合类(java.util)源码阅读笔记------HashMap

JAVA 集合类(java.util)源码阅读笔记------WeakHashMap

JAVA 集合类(java.util)源码阅读笔记------Stack

源码阅读(30):Java中线程安全的QueueDeque结构——概述