写在前面
本文是针对Java 1.8的源代码进行解析的,可能会和其他版本有所出入。
转载自http://blog.csdn.net/ljcitworld/article/details/52041836
全局变量
1. 默认容量
private static final int DEFAULT_CAPACITY = 10 ;
2. 空的对象数组
private static final Object[] EMPTY_ELEMENTDATA = {};
3.默认的空数组
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
4.存放数据的数组的缓存变量,不可序列化
transient Object[] elementData;
5.数组的大小
构造方法
1.带有容量initialCapacity的构造方法
源码解释:
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); } }
2.不带参数的构造方法
源码解释:
public ArrayList() { this .elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; }
3.带参数Collection的构造方法
源码解释:
参数c为一个Collection,Collection的实现类大概有以下几种常用类型:
List:元素可以重复的容器 Set: 元素不可重复的容器 Queue:结构是一个队列,先进先出
这个构造方法的意思是,将一个Collection实现类的对象转换为一个ArrayList,但是c容器装的内容必须为ArrayList装的内容的子类。例如,将一个装了String内容的HashSet转换为装了String内容的ArrayList,使得ArrayList的大小和值数组都是HashSet的大小和值数组。具体实现如下代码,首先调用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 { this .elementData = EMPTY_ELEMENTDATA; } }
方法
1.trimToSize()
说明: 将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++; if (size < elementData.length) { elementData = (size == 0 ) ? EMPTY_ELEMENTDATA : Arrays.copyOf(elementData, size); } }
2.size()
说明:
返回ArrayList的大小
源码解释:
直接返回size
public int size() { return size; }
3.isEmpty()
说明:
返回是否为空
源码解释:
直接返回判断size==0
public boolean isEmpty() { return size == 0 ; }
4.indexOf(Object o)
说明:
对象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 ; }
5.contains(Object o)
说明:
是否包含对象o
源码解释:
调用indexOf()方法得到下标,存在则下标>=0,不存在为-1,即只要比较下标和0的大小即可。
public boolean contains(Object o) { return indexOf(o) >= 0 ; }
6.lastIndexOf(Object o)
说明:
返回容器内出现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 ; }
7.clone()
说明:
返回此 ArrayList 实例的浅表副本。
源码解释:
public Object clone() { try { ArrayList<?> v = (ArrayList<?>) super .clone(); v.elementData = Arrays.copyOf(elementData, size); v.modCount = 0 ; return v; } catch (CloneNotSupportedException e) { throw new InternalError(e); } }
8.toArray()
说明:
ArrayList 实例转换为。
源码解释:
直接调用Arrays类的copyOf。
public Object[] toArray() { return Arrays.copyOf(elementData, size); }
9.toArray(T[] a)
说明:
将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) return (T[]) Arrays.copyOf(elementData, size, a.getClass()); System.arraycopy(elementData, 0 , a, 0 , size); if (a.length > size) a[size] = null ; return a; }
10.rangeCheck(int index)
说明:
测试index是否越界
源码解释:
private void rangeCheck( int index) { if (index >= size) throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); }
11.get(int index)
说明:
获取index位置的元素
源码解释:
先检查是否越界,然后返回ArrayList的elementData数组index位置的元素。
public E get( int index) { rangeCheck(index); return elementData(index); }
12.set(int index, E element)
说明:
设置index位置的元素值了element,返回该位置的之前的值
源码解释:
public E set( int index, E element) { rangeCheck(index); E oldValue = elementData(index); elementData[index] = element; return oldValue; }
13.ensureCapacityInternal(int minCapacity)
说明:
得到最小扩容量
源码解释:
private void ensureCapacityInternal( int minCapacity) { if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity); } ensureExplicitCapacity(minCapacity); }
14.ensureExplicitCapacity(int minCapacity)
说明:
判断是否需要扩容
源码解释:
private void ensureExplicitCapacity( int minCapacity) { modCount++; if (minCapacity - elementData.length > 0 ) grow(minCapacity); }
15.grow()方法
说明:
帮助ArrayList动态扩容的核心方法
源码解释:
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8 ; private void grow( int minCapacity) { int oldCapacity = elementData.length; int newCapacity = oldCapacity + (oldCapacity >> 1 ); if (newCapacity - minCapacity < 0 ) newCapacity = minCapacity; if (newCapacity - MAX_ARRAY_SIZE > 0 ) newCapacity = hugeCapacity(minCapacity); elementData = Arrays.copyOf(elementData, newCapacity); }
16.add(E e)
说明:
添加元素e
源码解释:
public boolean add(E e) { ensureCapacityInternal(size + 1 ); elementData[size++] = e; return true ; }
17.add(int index, E element)
说明:
在ArrayList的index位置,添加元素element
源码解释:
public void add( int index, E element) { rangeCheckForAdd(index); ensureCapacityInternal(size + 1 ); System.arraycopy(elementData, index, elementData, index + 1 , size - index); elementData[index] = element; size++; }
18.remove(int index)
说明:
在ArrayList的移除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 ; return oldValue; }
19.remove(Object o)
说明:
在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 ; }
20.clear()
说明:
设置全部元素为null值,并设置size为0。
源码解释:
可见clear操作并不是从空间内删除,只是设置为null值,等待垃圾回收机制来回收而已,把size设置为0,以便我们不会浏览到null值的内存空间。
public void clear() { modCount++; for ( int i = 0 ; i < size; i++) elementData[i] = null ; size = 0 ; }
21.addAll(Collection<? extends E> c)
说明:
将Collection c的全部元素添加到ArrayList中
源码解释:
public boolean addAll(Collection<? extends E> c) { Object[] a = c.toArray(); int numNew = a.length; ensureCapacityInternal(size + numNew); System.arraycopy(a, 0 , elementData, size, numNew); size += numNew; return numNew != 0 ; }
22.addAll(int index, Collection<? extends E> c)
说明:
从第index位开始,将c全部拷贝到ArrayList
源码解释:
public boolean addAll( int index, Collection<? extends E> c) { rangeCheckForAdd(index); Object[] a = c.toArray(); int numNew = a.length; ensureCapacityInternal(size + numNew); 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 ; }
24.batchRemove(Collection<?> c, boolean complement)
说明:
根据complement值,将ArrayList中包含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) elementData[w++] = elementData[r]; } finally { if (r != size) { System.arraycopy(elementData, r, elementData, w, size - r); w += size - r; } if (w != size) { for ( int i = w; i < size; i++) elementData[i] = null ; modCount += size - w; size = w; modified = true ; } } return modified; }
25.removeAll(Collection<?> c)
说明:
ArrayList移除c中的所有元素
源码解释:
public boolean removeAll(Collection<?> c) { Objects.requireNonNull(c); return batchRemove(c, false ); }
26.retainAll(Collection<?> c)
说明:
和removeAll相反,仅保留c中所有的元素
源码解释:
public boolean retainAll(Collection<?> c) { Objects.requireNonNull(c); return batchRemove(c, true ); }
27.iterator()
说明: 返回一个Iterator对象,Itr为ArrayList的一个内部类,其实现了Iterator<E>接口
代码解释:
public Iterator<E> iterator() { return new Itr(); }
28.listIterator()
说明:
返回一个ListIterator对象,ListItr为ArrayList的一个内部类,其实现了ListIterator<E> 接口
源码解释:
public ListIterator<E> listIterator() { return new ListItr( 0 ); }
29.listIterator(int index)
说明:
返回一个从index开始的ListIterator对象
源码解释:
public ListIterator<E> listIterator( int index) { if (index < 0 || index > size) throw new IndexOutOfBoundsException( "Index: " +index); return new ListItr(index); }
30.subList(int fromIndex, int toIndex)
说明:
根据两个参数,获取到一个子序列
源码解释:
public List<E> subList( int fromIndex, int toIndex) { subListRangeCheck(fromIndex, toIndex, size); 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的数组进行的,并没有创建新的数组。
最后一个比较个人比较少接触,大家需要自行度娘。
End
笔者技术真的是一般般,写这个为了加深理解的同时给害怕看源代码的朋友一点鼓励,所以笔者在写的过程中有查阅很多资料来努力减少错误,但是如有错漏之处,希望大神们指出,我会第一时间修改,以免误人子弟,也希望和笔者一样基础不够好的朋友不要畏惧看源码,源码看起来并不会很难,而且多看源代码会对Java更深刻的理解。