本文是针对Java 1.8的源代码进行解析的,可能会和其余版本有所出入。java
**继承:**AbstractList数组
**实现:**List<E>, RandomAccess, Cloneable, Serializable接口缓存
public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable{ }
private static final int DEFAULT_CAPACITY = 10;
private static final Object[] EMPTY_ELEMENTDATA = {};
// 无参构造函数建立的数组 private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
transient Object[] elementData;
private int size;
源码解释:多线程
public ArrayList(int initialCapacity) { // 若是初始化时ArrayList大小大于0 if (initialCapacity > 0) { // new一个该大小的object数组赋给elementData this.elementData = new Object[initialCapacity]; } else if (initialCapacity == 0) { // 若是大小为0 // 将空数组赋给elementData this.elementData = EMPTY_ELEMENTDATA; } else { // 小于0 // 则抛出IllegalArgumentException异常 throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity); } }
源码解释:dom
public ArrayList() { // 直接将空数组赋给elementData this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; }
源码解释:函数
参数c为一个Collection,Collection的实现类大概有如下几种经常使用类型:测试
这个构造方法的意思是,将一个Collection实现类的对象转换为一个ArrayList,可是c容器装的内容ui
必须为ArrayList装的内容的子类。例如,将一个装了String内容的HashSet转换为装了String内容的this
ArrayList,使得ArrayList的大小和值数组都是HashSet的大小和值数组。具体实现以下代码,首先调.net
用c(Collection的具体实现类)的toArray方法,具体你们能够看各个实现类的toArray方法,可是大
概意思都是将c容器转换为object类型的数组,由于它们的返回值都是object[]。之于下面的两个判断
是当获得的elementData的类名不是Object类名的时候或者是长度为0的时候才会执行。
public ArrayList(Collection<? extends E> c) { elementData = c.toArray(); if ((size = elementData.length) != 0) { if (elementData.getClass() != Object[].class) elementData = Arrays.copyOf(elementData, size, Object[].class); } else { // replace with empty array. this.elementData = EMPTY_ELEMENTDATA; } }
**说明:**将ArrayList的容量设置为当前size的大小。首先须要明确一个概念,ArrayList的size就是ArrayList的元素个数,length是ArrayList申请的内容空间长度。ArrayList每次都会预申请多一点空间,以便添加元素的时候不须要每次都进行扩容操做,例如咱们的元素个数是10个,它申请的内存空间一定会大于10,即length>size,而这个方法就是把ArrayList的内存空间设置为size,去除没有用到的null值空间。这也就是咱们为何每次在获取数据长度是都是调用list.size()而不是list.length()。
**源码解释:**首先modCount是从类 java.util.AbstractList 继承的字段,这个字段主要是为了防止在多线程操做的状况下,List发生结构性的变化,什么意思呢?就是防止一个线程正在迭代,另一个线程进行对List进行remove操做,这样当咱们迭代到最后一个元素时,很明显此时List的最后一个元素为空,那么这时modCount就会告诉迭代器,让其抛出异常 ConcurrentModificationException。
若是没有这一个变量,那么系统确定会报异常ArrayIndexOutOfBoundsException,这样的异常显然不是应该出现的(这些运行时错误都是使用者的逻辑错误致使的,咱们的JDK那么高端,不会出现使用错误,咱们只抛出使用者形成的错误,而这个错误是设计者应该考虑的),为了不出现这样的异常,定义了检查。
(引用自:郭无意,详情能够看他在知乎的回答:https://www.zhihu.com/question/24086463/answer/64717159)。
public void trimToSize() { modCount++; // 若是size小于length if (size < elementData.length) { // 从新将elementData设置大小为size elementData = (size == 0) ? EMPTY_ELEMENTDATA : Arrays.copyOf(elementData, size); } }
**说明:**返回ArrayList的大小
**源码解释:**直接返回size
public int size() { return size; }
**说明:**返回是否为空
**源码解释: **直接返回判断size==0
public boolean isEmpty() { return size == 0; }
**说明:**对象o在ArrayList中的下标位置,若是存在返回位置i,不存在返回-1
**源码解释:**遍历ArrayList的大小,比较o和容器内的元素,若相等,则返回位置i,若遍历完都不相等,返回-1
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; }
**说明:**是否包含对象o
**源码解释:**调用indexOf()方法获得下标,存在则下标>=0,不存在为-1,即只要比较下标和0的大小便可。
public boolean contains(Object o) { return indexOf(o) >= 0; }
**说明:**返回容器内出现o的最后一个位置
**源码解释:**从后向前遍历,获得第一个出现对象o的位置,不存在则返回-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 { // 调用父类(翻看源码可见是Object类)的clone方法获得一个ArrayList副本 ArrayList<?> v = (ArrayList<?>) super.clone(); // 调用Arrays类的copyOf,将ArrayList的elementData数组赋值给副本的elementData数组 v.elementData = Arrays.copyOf(elementData, size); v.modCount = 0; // 返回副本v return v; } catch (CloneNotSupportedException e) { throw new InternalError(e); } }
**说明:**ArrayList 实例转换为。
**源码解释:**直接调用Arrays类的copyOf。
public Object[] toArray() { return Arrays.copyOf(elementData, size); }
**说明:**将ArrayList里面的元素赋值到一个数组中去
**源码解释:**若是a的长度小于ArrayList的长度,直接调用Arrays类的copyOf,返回一个比a数组长度要大的新数组,里面元素就是ArrayList里面的元素;若是a的长度比ArrayList的长度大,那么就调用System.arraycopy,将ArrayList的elementData数组赋值到a数组,而后把a数组的size位置赋值为空。 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; }
**说明:**测试index是否越界
源码解释:
private void rangeCheck(int index) { // 若是下标超过ArrayList的数组长度 if (index >= size) // 抛出IndexOutOfBoundsException异常 throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); }
**说明:**获取index位置的元素
**源码解释:**先检查是否越界,而后返回ArrayList的elementData数组index位置的元素。
public E get(int index) { // 检查是否越界 rangeCheck(index); // 返回ArrayList的elementData数组index位置的元素 return elementData(index); }
**说明:**设置index位置的元素值了element,返回该位置的以前的值
源码解释:
public E set(int index, E element) { // 检查是否越界 rangeCheck(index); // 调用elementData(index)获取到当前位置的值 E oldValue = elementData(index); // 将element赋值到ArrayList的elementData数组的第index位置 elementData[index] = element; return oldValue; }
**说明:**获得最小扩容量
源码解释:
private void ensureCapacityInternal(int minCapacity) { if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { // 获取默认的容量和传入参数的较大值 minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity); } ensureExplicitCapacity(minCapacity); }
**说明:**判断是否须要扩容
源码解释:
private void ensureExplicitCapacity(int minCapacity) { modCount++; // 若是最小须要空间比elementData的内存空间要大,则须要扩容 if (minCapacity - elementData.length > 0) grow(minCapacity); }
**说明:**帮助ArrayList动态扩容的核心方法
源码解释:
// MAX_VALUE为231-1,MAX_ARRAY_SIZE 就是获取Java中int的最大限制,以防止越界 private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; private void grow(int minCapacity) { // 获取到ArrayList中elementData数组的内存空间长度 int oldCapacity = elementData.length; // 扩容至原来的1.5倍 int newCapacity = oldCapacity + (oldCapacity >> 1); // 再判断一下新数组的容量够不够,够了就直接使用这个长度建立新数组, // 不够就将数组长度设置为须要的长度 if (newCapacity - minCapacity < 0) newCapacity = minCapacity; // 判断有没超过最大限制 if (newCapacity - MAX_ARRAY_SIZE > 0) newCapacity = hugeCapacity(minCapacity); // 调用Arrays.copyOf方法将elementData数组指向新的内存空间时newCapacity的连续空间 // 并将elementData的数据复制到新的内存空间 elementData = Arrays.copyOf(elementData, newCapacity); }
**说明:**添加元素e
源码解释:
public boolean add(E e) { // 扩容 ensureCapacityInternal(size + 1); // 将e赋值给elementData的size+1的位置。 elementData[size++] = e; return true; }
**说明:**在ArrayList的index位置,添加元素element
源码解释:
public void add(int index, E element) { // 判断index是否越界 rangeCheckForAdd(index); // 扩容 ensureCapacityInternal(size + 1); // 将elementData从index位置开始,复制到elementData的index+1开始的连续空间 System.arraycopy(elementData, index, elementData, index + 1, size - index); // 在elementData的index位置赋值element elementData[index] = element; // ArrayList的大小加一 size++; }
**说明:**在ArrayList的移除index位置的元素
源码解释:
public E remove(int index) { // 判断是否越界 rangeCheck(index); modCount++; // 读取旧值 E oldValue = elementData(index); // 获取index位置开始到最后一个位置的个数 int numMoved = size - index - 1; if (numMoved > 0) // 将elementData数组index+1位置开始拷贝到elementData从index开始的空间 System.arraycopy(elementData, index+1, elementData, index, numMoved); // 使size-1 ,设置elementData的size位置为空,让GC来清理内存空间 elementData[--size] = null; // clear to let GC do its work return oldValue; }
**说明:**在ArrayList的移除对象为O的元素,跟indexOf方法思想基本一致
源码解释:
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; }
**说明:**设置所有元素为null值,并设置size为0。
**源码解释:**可见clear操做并非从空间内删除,只是设置为null值,等待垃圾回收机制来回收而已,把size设置为0,以便咱们不会浏览到null值的内存空间。
public void clear() { modCount++; // clear to let GC do its work for (int i = 0; i < size; i++) elementData[i] = null; size = 0; }
**说明:**将Collection c的所有元素添加到ArrayList中
源码解释:
public boolean addAll(Collection<? extends E> c) { // 将c转换为数组a Object[] a = c.toArray(); // 获取a占的内存空间长度赋值给numNew int numNew = a.length; // 扩容至size + numNew ensureCapacityInternal(size + numNew); // Increments modCount // 将a的第0位开始拷贝至elementData的size位开始,拷贝长度为numNew System.arraycopy(a, 0, elementData, size, numNew); // 将size增长numNew size += numNew; // 若是c为空,返回false,c不为空,返回true return numNew != 0; }
**说明:**从第index位开始,将c所有拷贝到ArrayList
源码解释:
public boolean addAll(int index, Collection<? extends E> c) { // 判断index大于size或者是小于0,若是是,则抛出IndexOutOfBoundsException异常 rangeCheckForAdd(index); // 将c转换为数组a Object[] a = c.toArray(); int numNew = a.length; // 扩容至size + numNew 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; }
**说明:**根据complement值,将ArrayList中包含c中元素的元素删除或者保留
源码解释:
private boolean batchRemove(Collection<?> c, boolean complement) { final Object[] elementData = this.elementData; // 定义一个w,一个r,两个同时右移 int r = 0, w = 0; boolean modified = false; try { // r先右移 for (; r < size; r++) // 若是c中不包含elementData[r]这个元素 if (c.contains(elementData[r]) == complement) // 则直接将r位置的元素赋值给w位置的元素,w自增 elementData[w++] = elementData[r]; } finally { // 防止抛出异常致使上面r的右移过程没完成 if (r != size) { // 将r未右移完成的位置的元素赋值给w右边位置的元素 System.arraycopy(elementData, r, elementData, w, size - r); // 修改w值增长size-r w += size - r; } if (w != size) { // 若是有被覆盖掉的元素,则将w后面的元素都赋值为null for (int i = w; i < size; i++) elementData[i] = null; modCount += size - w; // 修改size为w size = w; modified = true; } } return modified; }
**说明:**ArrayList移除c中的全部元素
源码解释:
public boolean removeAll(Collection<?> c) { // 若是c为空,则抛出空指针异常 Objects.requireNonNull(c); // 调用batchRemove移除c中的元素 return batchRemove(c, false); }
**说明:**和removeAll相反,仅保留c中全部的元素
源码解释:
public boolean retainAll(Collection<?> c) { Objects.requireNonNull(c); // 调用batchRemove保留c中的元素 return batchRemove(c, true); }
**说明:**返回一个Iterator对象,Itr为ArrayList的一个内部类,其实现了Iterator<E>接口
public Iterator<E> iterator() { return new Itr(); }
**说明:**返回一个ListIterator对象,ListItr为ArrayList的一个内部类,其实现了ListIterator<E> 接口
源码解释:
public ListIterator<E> listIterator() { return new ListItr(0); }
说明:返回一个从index开始的ListIterator对象
源码解释:
public ListIterator<E> listIterator(int index) { if (index < 0 || index > size) throw new IndexOutOfBoundsException("Index: "+index); return new ListItr(index); }
**说明:**根据两个参数,获取到一个子序列
源码解释:
public List<E> subList(int fromIndex, int toIndex) { // 检查异常 subListRangeCheck(fromIndex, toIndex, size); // 调用SubList类的构造方法 return new SubList(this, 0, fromIndex, toIndex); }
(1)private class Itr implements Iterator<E> (2)private class ListItr extends Itr implements ListIterator<E> (3)private class SubList extends AbstractList<E> implements RandomAccess (4)static final class ArrayListSpliterator<E> implements Spliterator<E>
ArrayList有四个内部类,
其中的Itr是实现了Iterator接口,同时重写了里面的hasNext(),next(),remove()等方法;
其中的ListItr继承Itr,实现了ListIterator接口,同时重写了hasPrevious(),nextIndex(), previousIndex(),previous(),set(E e),add(E e)等方法,因此这也能够看出了Iterator和ListIterator的区别,就是ListIterator在Iterator的基础上增长了添加对象,修改对象,逆向遍历等方法,这些是Iterator不能实现的。具体能够参考http://blog.csdn.net/a597926661/article/details/7679765。
其中的SubList继承AbstractList,实现了RandmAccess接口,类内部实现了对子序列的增删改查等方法,但它同时也充分利用了内部类的优势,就是共享ArrayList的全局变量,例如检查器变量modCount,数组elementData等,因此SubList进行的增删改查操做都是对ArrayList的数组进行的,并无建立新的数组。
最后一个比较我的比较少接触,你们须要自行度娘。
笔者技术真的是通常般,写这个为了加深理解的同时给惧怕看源代码的朋友一点鼓励,因此笔者在写的过程当中有查阅不少资料来努力减小错误,可是若有错漏之处,但愿大神们指出,我会第一时间修改,以避免误人子弟,也但愿和笔者同样基础不够好的朋友不要畏惧看源码,源码看起来并不会很难,并且多看源代码会对Java更深入的理解。