参数:
private static final int DEFAULT_CAPACITY = 10;//默认初始容量
/**
* 用户指定容量为0时返回数组
*/
private static final Object[] EMPTY_ELEMENTDATA = {};
/**
* 用户调用无参构造函数,在第一次添加元素时会以DEFAULT_CAPACITY扩容
*/
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
/**
* 保存数据,数组大小是arraylist的容量
* transient:表示对象序列化时不包括该数组(writeObject()和readObject()实现对数组序列化和反序列化)
* 原因:elementData是一个缓存数组,它通常会预留一些容量,等容量不足时再扩充容量,
* 那么有些空间可能就没有实际存储元素,采用上诉的方式来实现序列化时,
* 就可以保证只序列化实际存储的那些元素,而不是整个数组,从而节省空间和时间。
*/
transient Object[] elementData; // non-private to simplify nested class access
/**
* arraylist中实际大小(保存数据数量)
*/
private int size;
/**
* 可以分配数组的最大值
* OutOfMemoryError: 申请数组大小超过vm限制
*/
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
构造方法:
//创建指定初始容量的空arraylist
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);
}
}
//无参构造函数,在第一次加入元素时扩容至默认容量
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
// 创建一个包含collection的ArrayList
public ArrayList(Collection<? extends E> c) {
elementData = c.toArray();//将集合转为数组
if ((size = elementData.length) != 0) {//将数组长度赋值给size 并判断是否为0
if (elementData.getClass() != Object[].class)//如果数组不是objec[]t类型
elementData = Arrays.copyOf(elementData, size, Object[].class);//将数组拷贝到object[]数组
} else {
this.elementData = EMPTY_ELEMENTDATA;
}
}
扩容方法:
/**
* 扩展ArrayList容量(提供给使用者的方法) :为了确保数组容量大于minCapacity
* 作用:在 add 大量元素之前调用,以避免多次扩容
*/
public void ensureCapacity(int minCapacity) {
if (minCapacity > elementData.length
&& !(elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA
&& minCapacity <= DEFAULT_CAPACITY)) {
modCount++;
grow(minCapacity);
}
}
/**
* 数组扩容,当size等于数组长度并加入新数据时调用
*/
private Object[] grow() {
return grow(size + 1);
}
/**
*数组扩容
* @param minCapacity 指定最小容量
* @throws OutOfMemoryError 最小容量小于0抛出异常
*/
private Object[] grow(int minCapacity) {
return elementData = Arrays.copyOf(elementData,
newCapacity(minCapacity));//创建新数组,复制数据
}
/**
* 返回扩容后的数组容量(1.5*oldCapacity)
*/
private int newCapacity(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;//数组原有的长度
int newCapacity = oldCapacity + (oldCapacity >> 1);//扩容后的长度,1.5*oldCapacity
if (newCapacity - minCapacity <= 0) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA)//如果当前数组为空
return Math.max(DEFAULT_CAPACITY, minCapacity);//返回指定容量和默认容量的最大值
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return minCapacity;
}
return (newCapacity - MAX_ARRAY_SIZE <= 0)? newCapacity :hugeCapacity(minCapacity);
}
/**
* 当newCapacity超过MAX_ARRAY_SIZE时,调用此函数
*/
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE)
? Integer.MAX_VALUE
: MAX_ARRAY_SIZE;
}
查找元素索引:
/**
*判断元素在arraylist中的索引,不存在返回-1
*/
public int indexOf(Object o) {
return indexOfRange(o, 0, size);
}
/**
*判断元素在arraylist某一范围内的索引,不存在返回-1
*/
int indexOfRange(Object o, int start, int end) {
Object[] es = elementData;
if (o == null) {
for (int i = start; i < end; i++) {
if (es[i] == null) {
return i;
}
}
} else {
for (int i = start; i < end; i++) {
if (o.equals(es[i])) {
return i;
}
}
}
return -1;
}
/**
*查找元素在arraylist中的最后出现的索引,不存在返回-1
*/
public int lastIndexOf(Object o) {
return lastIndexOfRange(o, 0, size);
}
/**
*查找元素在arraylist中某一范围内最后出现的索引,不存在返回-1
*/
int lastIndexOfRange(Object o, int start, int end) {
Object[] es = elementData;
if (o == null) {
for (int i = end - 1; i >= start; i--) {//从数组末尾开始遍历
if (es[i] == null) {
return i;
}
}
} else {
for (int i = end - 1; i >= start; i--) {
if (o.equals(es[i])) {
return i;
}
}
}
return -1;
}
加入数据:
/**
*
*/
//向当前数组末尾加入元素
public boolean add(E e) {
modCount++;
add(e, elementData, size);
return true;
}
//判断size与当前数组大小,如果相等则扩容数组
private void add(E e, Object[] elementData, int s) {
if (s == elementData.length)
elementData = grow();
elementData[s] = e;
size = s + 1;
}
//向指定位置加入元素
public void add(int index, E element) {
//判断下标是否越界
rangeCheckForAdd(index);
modCount++;
final int s;
Object[] elementData;
if ((s = size) == (elementData = this.elementData).length)
elementData = grow();
//index后的元素向后移动一位
System.arraycopy(elementData, index,
elementData, index + 1,
s - index);
elementData[index] = element;
size = s + 1;
}
//判断下标与size的大小
private void rangeCheckForAdd(int index) {
if (index > size || index < 0)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
总结:
1.如果调用无参构造函数,先调用grow()扩容,扩容大小为默认容量
2.如果调用有参构造函数,如果当前size达到容量,先调用grow()扩容
注意:下面的代码第三行会报错java.lang.IndexOutOfBoundsException
在创建ArrayList对象时指定了初始容量5.
a.add(0,1):size=0,index=0, rangeCheckForAdd(int index)检查index与size的大小,执行成功
a.add(2,1):size=1, index=2,index>size,rangeCheckForAdd方法抛出异常
ArrayList<Integer> a = new ArrayList<>(5);
a.add(0,1);
a.add(2,1);
所以虽然在构造方法中指定了初始容量,仍然不能访问数组中size大小以后的位置。
System.arraycopy()与Arrays.copyOf():
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;
}
System.arraycopy():native方法,需要指定源数组、目标数组、起始索引和复制长度
public static native void arraycopy(Object src, int srcPos,
Object dest, int destPos,
int length);