ArrayList使我们在工作中用到最多的一个集合对象,其实现原理是基于数组,其中最最重要的方法也是ArrayList里面源码用到最多的就是System.arraycopy这个方法。
//这是一个本地方法,效率比较高,具体用法就不做描述
public static native void arraycopy(Object src, int srcPos,
Object dest, int destPos,
int length);
以下是个人源码的注释
public class MyArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable {
private static final long serialVersionUID = 8683452581122892189L;
//默认大小
private static final int DEFAULT_CAPACITY = 10;
//空数组,当构造函数传入0时,就用这个
private static final Object[] EMPTY_ELEMENTDATA = {};
//空数组,有且仅当无参构造时,是这个
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
//实际放数据的数组
transient Object[] elementData;
//实际数据数量,放一个加一,拿一个减一
private int size;
//带容量的构造方法
public MyArrayList(int initialCapacity) {
if (initialCapacity > 0) {
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) {
//如果传0则返回空数组
this.elementData = EMPTY_ELEMENTDATA;
} else {
throw new IllegalArgumentException("Illegal Capacity: " +
initialCapacity);
}
}
//无参构造,虽然也是返回空数组,但是这个空数组是带有标记的,即默认大小
public MyArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
//传入一个集合进行构造
public MyArrayList(Collection extends E> c) {
elementData = c.toArray();
if ((size = elementData.length) != 0) {
// 判断集合的toArray返回的是不是Object[]对象,应该来说都是的,如果不是,则把他变成Object[]
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
} else {
//集合为空时,用空数组代替
this.elementData = EMPTY_ELEMENTDATA;
}
}
//调整大小,例如,一开始数组大小是0,添加一个元素后,数组扩容变成了10.然后调用该方法会再次调整大小,使数组大小变成1
public void trimToSize() {
//操作数加1,目前还不知道这个是干嘛的
modCount++;
if (size < elementData.length) {
elementData = (size == 0)
? EMPTY_ELEMENTDATA
: Arrays.copyOf(elementData, size);
}
}
public void ensureCapacity(int minCapacity) {
//最小扩充,如果是无参构造的,则用为10,否则为0,因为只要不是无参构造的,那么就不是DEFAULTCAPACITY_EMPTY_ELEMENTDATA这个对象
//那么minExpand最小就是0,必须要进行判断操作。
int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA) ? 0 : DEFAULT_CAPACITY;
//判断操作
if (minCapacity > minExpand) {
ensureExplicitCapacity(minCapacity);
}
}
//只要不是DEFAULTCAPACITY_EMPTY_ELEMENTDATA,那么就要使用指定的最小容量
private static int calculateCapacity(Object[] elementData, int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
return Math.max(DEFAULT_CAPACITY, minCapacity);
}
return minCapacity;
}
private void ensureCapacityInternal(int minCapacity) {
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
//最大数组值
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
//数组增长方法
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
//扩容策略是原先大小+原先大小的一半
int newCapacity = oldCapacity + (oldCapacity >> 1);
//扩容之后仍然还是没有指定的容器大小大,那么直接使用指定的容器大小值
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
//扩容后的数组大小超出了MAX_ARRAY_SIZE
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);
}
//巨大数组方法,指当指定的容量大过设置好的MAX_ARRAY_SIZE值时,返回最大的Integer
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // 最小值应该要大于等于0,如果超出,则会<0,说明内存以及溢出!
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}
//元素个数
public int size() {
return size;
}
//元素个数是否为0
public boolean isEmpty() {
return size == 0;
}
//是否包含某个元素
public boolean contains(Object o) {
return indexOf(o) >= 0;
}
//首先看参数o是否为null,为null则==判断,否则用equals判断(所以自定义对象要重写equals和hashcode)
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;
}
//反正查找
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;
}
//仅仅只是克隆数组,元素还是原来的元素引用
public Object clone() {
try {
java.util.ArrayList> v = (java.util.ArrayList>) 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(e);
}
}
//返回元素数组,注意,该方法放回的类型是Object[],且返回的数组中是新创建的,但是里面的元素是List中元素的引用
public Object[] toArray() {
return Arrays.copyOf(elementData, size);
}
//上同,回自动判断传入数组的大小,自动适配!!所以直接传一个new T[]{}返回的就是元素数量的T[]
@SuppressWarnings("unchecked")
public 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;
}
//同一个包下可以操作
@SuppressWarnings("unchecked")
E elementData(int index) {
return (E) elementData[index];
}
//通过索引来获取元素
public E get(int index) {
rangeCheck(index);//首先检查索引是否正常
return elementData(index);
}
//指定索引和元素,来进行元素的替换,返回值是老的元素值
public E set(int index, E element) {
//首先检查索引是否正常
rangeCheck(index);
//获取原先的数据,等下返回
E oldValue = elementData(index);
//修改传入索引位置的元素的值
elementData[index] = element;
return oldValue;
}
//添加元素
public boolean add(E e) {
//确保在原来大小的基础上+1的大小值
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
//在指定索引插入,index不能大于size,即要么插在中间,要么插在最后一位。
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++;
}
//移除指定索引的元素,返回被移除的那个元素值
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;
}
//和indexOf类似,为什么不fastRemove(indexOf(o))?,可能需要记录modCount有关吧
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;
}
//快速移除,并未返回移除的那个元素的值
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 void clear() {
modCount++;//增加修改值
//遍历素组,让全部的元素都为空,为什么不直接elementData=EMPTY_ELEMENTDATA而是要一个个设置为null?
//是为了让垃圾回收工作。clear to let GC do its work
for (int i = 0; i < size; i++)
elementData[i] = null;
size = 0;
}
//添加全部,直接加载素组的最后面。
public boolean addAll(Collection extends E> c) {
Object[] a = c.toArray();
int numNew = a.length;
//数组容量的保证
ensureCapacityInternal(size + numNew); // Increments modCount
System.arraycopy(a, 0, elementData, size, numNew);
size += numNew;
return numNew != 0;
}
//指定索引位置插入一个集合
public boolean addAll(int index, Collection extends E> c) {
rangeCheckForAdd(index);
Object[] a = c.toArray();
int numNew = a.length;
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;
}
//指定移除的范围
protected void removeRange(int fromIndex, int toIndex) {
modCount++;
int numMoved = size - toIndex;
System.arraycopy(elementData, toIndex, elementData, fromIndex,
numMoved);
// clear to let GC do its work
int newSize = size - (toIndex - fromIndex);
for (int i = newSize; i < size; i++) {
//使之后的元素为null
elementData[i] = null;
}
size = newSize;
}
//索引是否大于size检查
private void rangeCheck(int index) {
if (index >= size)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
//索引检查
private void rangeCheckForAdd(int index) {
if (index > size || index < 0)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
//输出错误信息
private String outOfBoundsMsg(int index) {
return "Index: " + index + ", Size: " + size;
}
//批量移除,传入参数的元素,如果在集合中包括那么就移除
public boolean removeAll(Collection> c) {
Objects.requireNonNull(c);
return batchRemove(c, false);
}
//批量保留,传入参数的元素,如果在集合中包括那么就保留
public boolean retainAll(Collection> c) {
Objects.requireNonNull(c);
return batchRemove(c, true);
}
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 {
// Preserve behavioral compatibility with AbstractCollection,
// even if c.contains() throws.
if (r != size) {
System.arraycopy(elementData, r,
elementData, w,
size - r);
w += size - r;
}
if (w != size) {
// clear to let GC do its work
for (int i = w; i < size; i++)
elementData[i] = null;
modCount += size - w;
size = w;
modified = true;
}
}
return modified;
}
///以下省略
}