在平时Java,存储数据需要用到列表,而大多时候都能用到ArrayList,比如Mybatis查询数据列表,返回列表都是ArrayList,很多数据的存放也用到了ArrayList。
jdk 版本: 1.8
ArrayList 是基于大小可变的数组实现,并允许添加null值, 根据下标就能数据查询快。数组一旦初始化就确定好了大小,如果需要添加数据,就需要做数据的复制,这些操作比较耗时。
ArrayList数组的扩容、添加和删除需要用到数组的拷贝,主要用到了以下两个方法:
System.arraycopyArrays.copyOfSystem.arraycopy() 是Java的原生的静态方法,该方法将源数组元素拷贝到目标数组中去。
参数详解:
src源数组,起始索引为srcPos,个数为length,复制到起始索引为destPos的dest目标数组。比如:
int[] srcArray = new int[]{1,2,3,4,5,6};int[] desArray = new int[5];System.arraycopy(srcArray,1,desArray,2,3);System.out.println("desArray: " + Arrays.toString(desArray));输出:
[0, 0, 2, 3, 4]Arrays.copyOf本质也是调用System.arraycopy方法:
public static int[] copyOf(int[] original, int newLength) { int[] copy = new int[newLength]; System.arraycopy(original, 0, copy, 0, Math.min(original.length, newLength)); return copy;}首先创建一个新的数组copy,将original数组全部复制给copy数组。
// 底层数组transient Object[] elementData;// 数组个数大小private int size;// 默认空数组private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};ArrayList是基于数组的一个实现,elementData就是底层的数组。size 是记录数组的个数。public ArrayList() { this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;}无参构造方法,创建数据直接赋值一个空数组。
赋一个初始化容量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); }}initialCapacity大于零,新建长度initialCapacity的数组。initialCapacity等于零,新建一个空数组。添加数据有两个方法:
在列表尾部添加数据:
/** * Appends the specified element to the end of this list. */public boolean add(E e) { ensureCapacityInternal(size + 1); // Increments modCount!! elementData[size++] = e; return true;}ensureCapacityInternal 判断添加数据后的容量是否足够,如果不够,做扩容操作。
private void ensureCapacityInternal(int minCapacity) { ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));}private static int calculateCapacity(Object[] elementData, int minCapacity) { if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { return Math.max(DEFAULT_CAPACITY, minCapacity); } return minCapacity;}private void ensureExplicitCapacity(int minCapacity) { modCount++; // overflow-conscious code if (minCapacity - elementData.length > 0) grow(minCapacity);}ensureCapacityInternal 作用是判断容量当前容量是否足够存放新的数据,如果不够就做扩容操作。
calculateCapacity计算容量,如果数组为null,返回minCapacity和10的最大值,否则返回minCapacity。这个方法就是返回数组的大小。
调用无参构造方法
ArrayList(),再调用add()方法,首先数组容量会变成10。这也是为什么无参构造方法ArrayList()上面有会有注解Constructs an empty list with an initial capacity of ten.
ensureExplicitCapacity 判断需要的容量minCapacity大于当前数组的长度elementData.length,将会做扩容处理,也是调用grow方法:
private void grow(int minCapacity) { // overflow-conscious code 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); // 拷贝数组到新的长度数组 elementData = Arrays.copyOf(elementData, newCapacity);}group 主要做了两件事:
做完判断是否要做扩容之后,直接在size位置上赋值要添加的元素,然后size再自增。
elementData[size++] = e;10,其他容量返回当前数组size + 1。1.5倍,将数组赋值给长度为原来数组1.5倍的新数组。size赋值。此添加数据是在指定的下标添加数据。
public void add(int index, E element) { // 下标是否越界 rangeCheckForAdd(index); // 判断是否要扩容 ensureCapacityInternal(size + 1); // Increments modCount!! // 复制i到size的数据到i+1 到size +1 System.arraycopy(elementData, index, elementData, index + 1, size - index); elementData[index] = element; size++;}add(int index, E element) 在index下标添加数据,
index 是否在0 ~size之间。1.5倍扩容。index以后的数据全部往后移动一位。index 下标数据。
获取数据只有通过数组下标获取数据 get(int index):
public E get(int index) { //检查是否超过数组范围 rangeCheck(index); return elementData(index);}@SuppressWarnings("unchecked")E elementData(int index) { // 通过下标获取数据 return (E) elementData[index];}这里获取数据就比较简单:
删除列表中第一个匹配的元素:
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:
elementData[index]是否为空。equals是否匹配elementData[index]。上面判断都为true时,调用fastRemove方法:
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}移动数组数据,index+1 以及之后的数据往前移动一位,最后一位size-1赋值为null。

根据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; // clear to let GC do its work return oldValue;}System.arraycopy方法,System.arraycopy是将src源数组,起始索引为srcPos,个数为length,复制到起始索引为destPos的dest目标数组。ArrayList主要是基于Object[] elementData动态数组实现。add 添加数组首先判断是否需要扩容,需要扩容,长度扩大成原来的1.5倍。size赋值添加数据index往后移动一位,新数据添加到index上。get(int index)利用数组的特定,根据下标获取数据。remove(int index) 将index之后的数据全部往前移动一位,size - 1赋为null。