ArrayList 源码解析
基于jdk1.7
成员变量
private static final int DEFAULT_CAPACITY = 10; //默认初始容量
private static final Object[] EMPTY_ELEMENTDATA = {}; //空数组
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
transient Object[] elementData; //数组,存储数据
private int size; //ArrayList的长度,小于或者等于elementData的长度
protected transient int modCount = 0; // 列表被改变的次数
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; //默认数组最大大小,实际可为Integer.MAX_VALUE
构造函数
-
无参构造函数
//默认创建空数组; java1.7之后,数组扩容在add方法里面 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);
}
}
//接收集合对象
public ArrayList(Collection<? extends E> c) {
elementData = c.toArray();
if ((size = elementData.length) != 0) {
// c.toArray 可能不会返回 Object[] (see 6260652)
if (elementData.getClass() != Object[].class)
//扩容:将旧数组,从位置0开始copy,如果size>旧数组的长度,则保留数组默认值
//int[] a =[1,2,3,4,5]--->int[] b =[1,2,3,4,5,0,0,0,0,0]
// b = Arrays.copyOf(a, 10);
elementData = Arrays.copyOf(elementData, size, Object[].class);
} else {
//null
this.elementData = EMPTY_ELEMENTDATA;
}
}
常用方法
-
增
public boolean add(E e) { ensureCapacityInternal(size + 1); // 扩容:(size + 1)防止出现初始容量为1,扩容后容量还是为1的情况(此情况是由于Arraylist按照1.5倍导致) elementData[size++] = e; return true; }
public void add(int index, E element) { //检查角标是否越界 rangeCheckForAdd(index); ensureCapacityInternal(size + 1); // 扩容 // public static native void arraycopy(Object src, int srcPos,Object dest, int destPos,int length); // src:源数组; // srcPos:源数组要复制的起始位置; // dest:目的数组; // destPos:目的数组放置的起始位置; length:复制的长度。 // 理解:从src数组的srcPos位置开始复制length个元素,将复制到的元素从dest数组的destPos位置依次放置 // 实现原理: 先生成一个长度为length的临时数组,将fun数组中srcPos到srcPos+length-1之间的数据拷贝到临时数组中,再执行System.arraycopy(临时数组,0,fun,3,3). // 例:int[] arr = {1,2,3,4,5,6}; System.arraycopy(arr,2,arr,4,2);-->[1,2,3,4,3,4] System.arraycopy(elementData, index, elementData, index + 1,size - index); elementData[index] = element; size++; }
//扩容关键代码 private void ensureCapacityInternal(int minCapacity) { ensureExplicitCapacity(calculateCapacity(elementData, minCapacity)); } private static int calculateCapacity(Object[] elementData, int minCapacity) { //判断是否为空数组 if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { //比较minCapacity和默认容量大小,取较大值 return Math.max(DEFAULT_CAPACITY, minCapacity); } return minCapacity; } private void ensureExplicitCapacity(int minCapacity) { modCount++; // 防止溢出 if (minCapacity - elementData.length > 0) grow(minCapacity); } private void grow(int minCapacity) { // overflow-conscious code int oldCapacity = elementData.length; //原数组长度 int newCapacity = oldCapacity + (oldCapacity >> 1); //数组长度+数组长度×0.5 //判断数组扩容后的长度是否小于实际需要的长度(minCapacity新的元素的位置) if (newCapacity - minCapacity < 0) newCapacity = minCapacity; //判断是否超过数组最大大小 if (newCapacity - MAX_ARRAY_SIZE > 0) newCapacity = hugeCapacity(minCapacity); // 扩容 elementData = Arrays.copyOf(elementData, newCapacity); } //数组最大容量为Integer的最大值 private static int hugeCapacity(int minCapacity) { if (minCapacity < 0) // overflow throw new OutOfMemoryError(); return (minCapacity > MAX_ARRAY_SIZE) ?Integer.MAX_VALUE :MAX_ARRAY_SIZE; } //检查角标是否越界 private void rangeCheckForAdd(int index) { if (index > size || index < 0) throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); }
-
删
public E remove(int index) { rangeCheck(index); //检查角标是否越界 modCount++; E oldValue = elementData(index); //旧元素 int numMoved = size - index - 1; //需要往前移动的元素的个数 if (numMoved > 0) //判断要移除的是否为最后一个元素 //数组内部位置在index之后的元素向前移动 System.arraycopy(elementData, index+1, elementData, index,numMoved); elementData[--size] = null; // 将最后一个元素置空,让GC回收 return oldValue; //返回被移除的元素 }
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++) //调用对象自己的equals进行比较 if (o.equals(elementData[index])) { fastRemove(index); return true; } } return false; }
//和remove(int index)类似 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 E set(int index, E element) { rangeCheck(index); E oldValue = elementData(index); //获取旧元素 elementData[index] = element; //赋值 return oldValue; }
@SuppressWarnings("unchecked") E elementData(int index) { //elementData 元素默认为Object此处直接进行强制转换 return (E) elementData[index]; }
-
查
public E get(int index) { rangeCheck(index); return elementData(index); }
重要点
-
通过无参构造函数创建ArrayList时,数组默认长度为0,调用add方法后会进行扩容,默认初始大小为10,每次扩容1.5倍
-
扩容关键函数:
-
System.arraycopy(): 该方法用了 native 关键字,说明调用的是其他语言写的底层函数。 需要目标数组,将原数组拷贝到你自己定义的数组里,而且可以选择拷贝的起点和长度以及放入新数组中的位置
-
Arrays.copyOf(): copyOf() 是系统自动在内部新建一个数组,调用 arraycopy() 将 original 内容复制到 copy 中去,并且长度为 newLength。返回 copy; 即将原数组拷贝到一个长度为 newLength 的新数组中,并返回该数组。
-