源码基于JDB_1.8版本。
目录
构造函数1
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);
}
}
可以看出,ArrayList本质上就是一个数组,数据类型是Object。当传入的参数大于0时,创建一个大小为初始值的数组;如果参数等于0,则创建一个空数组
private static final Object[] EMPTY_ELEMENTDATA = {};
其他情况下,抛出异常。
构造函数2
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
不传参时,也同样创建一个空数组
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
构造函数3
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;
}
}
通过另一个Collection来初始化ArrayList。当这个Collection的类型也是数组类型时,直接通过=来赋值。如果不是,则通过Arrays.copyOf的方法来赋值。
contains(Object o)
public boolean contains(Object o) {
return indexOf(o) >= 0;
}
检测ArrayList是否包含某个对象,通过索引该对象在ArrayList中的位置来判断是否包含。如果位置>=零,说明对象在ArrayList中。其中indexOf(Object o)如下:
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,遇到第一个值为null的位置时,返回该位置的索引;
当该对象不为null时,遍历ArrayList,遇到第一个值与该对象相等的位置时,返回该位置的索引。
当遍历完所有位置都未找到相等的位置时,返回-1。
lastIndexOf(Object o)
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中的最后一个位置。该方法和indexOf(Object o)的方法基本一样,只不过遍历的时候是从ArrayList的末尾处往前遍历。
toArray()
public Object[] toArray() {
return Arrays.copyOf(elementData, size);
}
ArrayList转换成字节数组,直接调用Arrays.copyOf方法。
get(int index)
public E get(int index) {
rangeCheck(index);
return elementData(index);
}
该方法获取ArrayList指定位置的值,调用了rangeCheck(index)和elementData(index)。
private void rangeCheck(int index) {
if (index >= size)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
该方法校验index的值是否超过ArrayList,超过就抛出数组越界错误。
@SuppressWarnings("unchecked")
E elementData(int index) {
return (E) elementData[index];
}
该方法直接返回数组在指定位置的值,因为ArrayList本质上就是数组。
set(int index, E element)
public E set(int index, E element) {
rangeCheck(index);
E oldValue = elementData(index);
elementData[index] = element;
return oldValue;
}
先检查传入的索引参数是否越界。再获取ArrayList中原来在这个位置上的值oldValue,然后再将这个位置上的值替换成新的值,返回旧值oldValue。
add(E e)
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
先调用ensureCapacityInternal,然后将数组的最大位置的下一位设置成传入的值,返回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);
}
该方法的作用是确认组成ArrayList里的元素个数是否超过数组的容量。如果数组是空数组,则minCapacity取DEFAULT_CAPACITY和传入的参数中比较大的那个值。例如new ArrayList(2),而数组默认的初始值是10,则minCapacity赋值为10。如果minCapacity大于数组的长度,这个时候需要将数组扩容,因为数组的大小是不可变的,因此需要重新创建一个数组,将原数组的内容赋值过去。扩容方法是grow(minCapacity)。modCount记录集合的修改次数,也就每次add或者remove它的值都会加1。
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);
}
每次按照原数组50%的大小进行扩容。如果增大50%后的数组大小依然小于传入的参数minCapacity的话,则就将该参数minCapacity作为新数组的大小(一般不会发生)。如果新数组的大小超过了Integer.MAX_VALUE - 8,调用hugeCapacity
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}
如果minCapacity超过了Integer.MAX_VALUE就会变成负数,此时抛出内存溢出;
否则,Integer.MAX_VALUE - 8 < minCapacity < Integer.MAX_VALUE,这个时候,创建一个Integer.MAX_VALUE长度的数组。
然后通过Arrays.copyOf创建一个新数组,将原数组复制过去。
add(int index, E element)
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++;
}
作用:在指定位置插入元素。
首先通过rangeCheckForAdd检查位置索引是否合法
private void rangeCheckForAdd(int index) {
if (index > size || index < 0)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
如果位置索引大于ArrayList的元素个数或者小于0,抛出数组越界异常。
再通过ensureCapacityInternal检查数组是否已满、是否需要扩容(前面add方法已介绍过)。
然后调用System.arraycopy方法,这是一个native方法,作用是:将数组中index处往后的所有元素都往后面移动一个位置,一共需要移动size - index个元素。然后再将新元素放在数组中index的位置上,同时ArrayList的元素个数加1。
clone()
public Object clone() {
try {
ArrayList<?> v = (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);
}
}
通过Arrays.copyOf创建一个大小一样的新数组,将原数组复制过去,同时将modCount重置为0。