public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable
ArrayList是一个数组队列,至关于一个动态数组,和数组相比,它能够扩容。它继承了AbstractList,实现了List,RandomAccess,Cloneable,Serializable接口。java
ArrayList继承了AbstractList,实现了List,它是一个数组队列,拥有了基本的添加,删除,修改,遍历查询等功能。数组
ArrayList实现RandomAccess接口,提供随机访问功能,RandmoAccess是java中用来被List实现,为List提供快速访问功能的,ArrayList能够根据序号快速访问元素对象。安全
ArrayList 实现了Cloneable接口,即覆盖了函数clone(),能被克隆。dom
ArrayList 实现了Serializable接口,说明ArrayList能被序列化进行传输。函数
特别的ArrayList是线程不安全的。性能
//默认的数组存储容量 private static final int DEFAULT_CAPACITY = 10; //当指定数组的容量为0的时候使用这个变量赋值 private static final Object[] EMPTY_ELEMENTDATA = {}; //默认的实例化的时候使用此变量赋值 private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}; //真正存放数据的对象数组,并不被序列化 transient 关键字修饰的属性不被序列化 transient Object[] elementData; // non-private to simplify nested class access //数组中的真实元素个数,它小于或等于elementData.length private int size; //数组中最大存放元素的个数 private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; /** * 构造函数一,若是指定容量就分配指定容量的大小 * 没有指定就使用EMPTY_ELEMENTDATA赋值 */ public ArrayList(int initialCapacity) { if (initialCapacity > 0) { this.elementData = new Object[initialCapacity]; } else if (initialCapacity == 0) { this.elementData = EMPTY_ELEMENTDATA; } else { throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity); } } /** * 构造函数二,使用默认的DEFAULTCAPACITY_EMPTY_ELEMENTDATA赋值 */ public ArrayList() { this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; } /** * 构造一个传入的集合,做为数组的数据 */ public ArrayList(Collection<? extends E> c) { elementData = c.toArray(); if ((size = elementData.length) != 0) { // c.toArray might (incorrectly) not return Object[] (see 6260652) if (elementData.getClass() != Object[].class) elementData = Arrays.copyOf(elementData, size, Object[].class); } else { // replace with empty array. this.elementData = EMPTY_ELEMENTDATA; } }
添加有两个方法,第一个add(E e)方法的调用链涉及5个方法,分别以下:this
public boolean add(E e) { ensureCapacityInternal(size + 1); // Increments modCount!! 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); }
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); }
private static int hugeCapacity(int minCapacity) { if (minCapacity < 0) // overflow throw new OutOfMemoryError(); return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE; }
这里一步步分析,在调用了add(E e)的方法第一步,咱们看到了它调用了ensureCapacityInternal(size + 1)方法,在这个方法里面首先判断了数组是否是一个长度为0的空数组,若是是的话就给它容量赋值为默认的容量大小也就是10,而后调用了ensureExplicitCapacity方法,这个方法里面记录了modCount+1以后,并判断了当前的容量是否小于数组当前的长度,若是大于当前数组的长度就开始进行扩容操做调用方法 grow(minCapacity),扩容的长度是增长了原来数组数组的一半大小,而后并判断了是否达到了数组扩容的上限并赋值,接着把旧数组的数据拷贝到扩容后的新数组里面再次赋值给旧数组,最后把新添加的元素赋值给了扩容后的size+1的位置里面。spa
接着看第2个add方法:线程
public void add(int index, E element) { rangeCheckForAdd(index);//判断数组下标是否越界 ensureCapacityInternal(size + 1); // Increments modCount!! //这里面用到了 System.arraycopy方法,参数含义以下: //(原数组,原数组的开始位置,目标数组,目标数组的的开始位置,拷贝的个数) System.arraycopy(elementData, index, elementData, index + 1, size - index); elementData[index] = element; size++; }
这个方法的意思是给指定位置添加一个元素,ArrayList首先检查是否索引越界,若是没有越界,就检查是否须要扩容,而后将index位置以后的全部数据,总体拷贝到index+1开始的位置,而后就能够把新加入的数据放到index这个位置,而index前面的数据不须要移动,在这里咱们能够看到给指定位置插入数据ArrayList是一项大动做比较耗性能。code
根据下标删除指定未知的元素
public E remove(int index) { //检测下标是否越界 rangeCheck(index); //记录修改次数 modCount++; //获取移除位置上的值 E oldValue = elementData(index); //获取要移动元素的个数 int numMoved = size - index - 1; //拷贝移动的全部数据到index位置上 if (numMoved > 0) System.arraycopy(elementData, index+1, elementData, index, numMoved); //把size-1的位置的元素赋值null,方便gc垃圾回收 elementData[--size] = null; // clear to let GC do its work //最终返回被删除的数据 return oldValue; }
根据元素删除
public boolean remove(Object o) { if (o == null) {//移除null值 for (int index = 0; index < size; index++) if (elementData[index] == null) {//找到集合里面第一个等于null的元素 fastRemove(index);//移除 return true; } } else { for (int index = 0; index < size; index++) if (o.equals(elementData[index])) {//非null状况下,遍历每个元素经过equals比较 fastRemove(index);//移除 return true; } } return false; } /* * 该方法与经过下标移除的原理同样,总体左移 */ 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 E get(int index) { //检测下标是否越界 rangeCheck(index); return elementData(index); }
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 contains(Object o) { return indexOf(o) >= 0; } /** * */ public int indexOf(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; }
这个没啥好说的
源码不复杂,底层就是一个数组,不过这个数组能够扩容。容许添加全部元素包括null,还有ArrayList的全部方法都是线程不安全的,能够用 Collections.synchronizedList(list) 转线程安全。