ArrayList源码分析(1.7.0_80)

来源:互联网 发布:软件项目任务书 编辑:程序博客网 时间:2024/06/15 20:23

定义

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

底层实现:数组

  • AbstractList 实现List的基本操作
  • List 定义List的基本方法
  • RandomAccess 一种标志位,类似于clone标志,作用:
    JDK中说的很清楚,在对List特别是Huge size的List的遍历算法中,要尽量来判断是属于RandomAccess(如ArrayList)还是Sequence List (如LinkedList),因为适合RandomAccess List的遍历算法,用在Sequence List上就差别很大,常用的作法就是:
    要作一个判断:
    if (list instance of RandomAccess) {
    for(int m = 0; m < list.size(); m++){}
    }else{
    Iterator iter = list.iterator();
    while(iter.hasNext()){}
    }
    参考这里

属性

 private transient Object[] elementData;

transient :此字段是否可以被序列化
elementData : ArrayList底层实现数组,初始大小10

方法

trimToSize

 public void trimToSize() {        modCount++;        if (size < elementData.length) {            elementData = Arrays.copyOf(elementData, size);        }    }

作用:重新定义数组初始化大小
modCount:list被改变次数,定义在iterator中,用以判断list是否被同步修改,所以ArrayList不是同步安全的,可以使用以下代码包装一次list使其成为同步安全的:

 List list = Collections.synchronizedList(new ArrayList(...)); 
/**         * The modCount value that the iterator believes that the backing         * List should have.  If this expectation is violated, the iterator         * has detected concurrent modification.         */        int expectedModCount = modCount;

若两者不相等抛出ConcurrentModificationException异常
重新定义数组大小,只是用来定义数组的容量,不代表数组中有多少个元素,所以

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

用以上方法初始化ArrayList不能初始化ArrayList大小,一般用来当ArrayList数据较大时使用,避免ArrayList底层数组替换。

add(E e)

在list末尾添加元素

public boolean add(E e) {        ensureCapacityInternal(size + 1);  // Increments modCount!!        elementData[size++] = e;        return true;    }

ensureCapacityInternal:判断是否需要扩容并扩容,modCount自增1
elementData[size++] = e; 新增元素加入数组
扩容方法:

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

扩容:newCapacity = oldCapacity + (oldCapacity >> 1) 一次扩容一半,至于为什么每次扩容1.5倍,效率问题,扩容之后并将源数据copy到新数组中。

add(int index, E element)

在指定位置添加元素

 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++;    }

rangeCheckForAdd: 检查下标是否越界
System.arraycopy:将数组中index至末尾数据右移,耗时

  public static native void arraycopy(Object src,  int  srcPos,                                        Object dest, int destPos,                                        int length);

将数组src中以srcPos开始长度为length的数据复制到dest中,从destPos开始粘贴;

余下add方法都是以以上两种方法为基础

contains(Object o)

数组中是否包含o,正序查找

indexOf(Object o)

返回list中第一次出现o的下标,正序查找,无返回-1。

lastIndexOf(Object o)

     返回list从末尾第一次出现o的下标,逆序查找,无返回-1。

clone()

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的clone属于浅拷贝,从这句v.elementData = Arrays.copyOf(elementData, size);ArrayList的clone只是将原数组中数据的地址复制到新数组中

参考博文:
链接一
链接二