文章目录
ArrayList源码
基于java 1.8
List存储一个有序元素合集
List接口的实现类有: ArrayList,LinkedList,Vector,Stack
ArrayList一个数组型的List
数组
transient Object[] elementData;
默认容量
private static final int DEFAULT_CAPACITY = 10;
构造函数
//initialCapacity 创建时指定容量
public ArrayList(int initialCapacity) {
if (initialCapacity > 0) {
// 创建新的Object数组
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) {
// 一个 Object[] EMPTY_ELEMENTDATA = {} 空数组
this.elementData = EMPTY_ELEMENTDATA;
} else {
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
}
}
add方法
public boolean add(E e) {
// 首先容量+1
ensureCapacityInternal(size + 1);
// 把新元素加到最后
elementData[size++] = e;
return 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++;
//当新容量大于当前长度就需要扩容
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
- ensureCapacityInternal(size + 1);确保内部容量,不够则扩容
- 当前数组为空时,扩容的长度为默认容量大小
- 当初始化没有设置容量时,第一次添加元素是需要扩容的
扩容
private void grow(int minCapacity) {
// 原来的数组长度
int oldCapacity = elementData.length;
// 需要扩容的长度=原数组长度+0.5个原数组长度
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
// MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; 等于2^31-1-8
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// 拷贝原数组到新数组
elementData = Arrays.copyOf(elementData, newCapacity);
}
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0)
throw new OutOfMemoryError();
// 2^31-1还是2^31-1-8
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}
- 扩容的大小为原长度+1/2的原长度
- 如果扩容长度比传入的最小容量小,则使用最小容量,如果扩容长度超过设定的最大容量,则实用最大正整数
- 初始化默认长度为10,当添加到11个长度时,容量为15
- copy方法调用的是System.arraycopy();
remove方法
public E remove(int index) {
// 检查下标,是不是大于数组长度
rangeCheck(index);
modCount++;
E oldValue = elementData(index);
// 需要移动的元素 如:10个长度,需要删除的索引为3,算出需要移动的元素为6个
int numMoved = size - index - 1;
if (numMoved > 0)
//参数为:原数组,原索引从第四个开始copy,新元素,目标索引,长度
System.arraycopy(elementData, index+1, elementData, index,numMoved);
// 设置最后一个元素为null
elementData[--size] = null;
return oldValue;
}
private void rangeCheck(int index) {
if (index >= size)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
- System.arraycopy()方法中原数组和新数组设为同一个数组,可以实现数组元素间的移动
- remove()方法设为null值的都是最后一个元素
clear方法
public void clear() {
modCount++;
// 循环把所有数组元素设置为null
for (int i = 0; i < size; i++)
elementData[i] = null;
// size设置为0
size = 0;
}
size方法
private int size;
public int size() {
//ArrayList中的size变量
return size;
}
isEmpty方法
public boolean isEmpty() {
return size == 0;
}
subList内部类
private final AbstractList<E> parent;
private final int parentOffset;
private final int offset;
int size;
SubList(AbstractList<E> parent,
int offset, int fromIndex, int toIndex) {
// 原始ArrayList
this.parent = parent;
// 开始的索引
this.parentOffset = fromIndex;
// 偏移量
this.offset = offset + fromIndex;
// subList的长度
this.size = toIndex - fromIndex;
this.modCount = ArrayList.this.modCount;
}
- 在构造方法中this.parent = parent,意味着对象为原始list
- this.parentOffset = fromIndex;和this.offset = offset + fromIndex;为原始索引
生成subList对象
public List<E> subList(int fromIndex, int toIndex) {
//检查边界
subListRangeCheck(fromIndex, toIndex, size);
//生成的时SubList对象,注意this
return new SubList(this, 0, fromIndex, toIndex);
}
static void subListRangeCheck(int fromIndex, int toIndex, int size) {
if (fromIndex < 0)
throw new IndexOutOfBoundsException("fromIndex = " + fromIndex);
if (toIndex > size)
throw new IndexOutOfBoundsException("toIndex = " + toIndex);
if (fromIndex > toIndex)
throw new IllegalArgumentException("fromIndex(" + fromIndex +") > toIndex(" + toIndex + ")");
}
add方法
public void add(int index, E e) {
// 检查索引防止溢出
rangeCheckForAdd(index);
checkForComodification();
// 原始ArraryList被添加一个元素
parent.add(parentOffset + index, e);
this.modCount = parent.modCount;
this.size++;
}
private void rangeCheckForAdd(int index) {
if (index < 0 || index > this.size)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
- parent.add(parentOffset + index, e);原始list将被添加一个元素
- remove方法中E result = parent.remove(parentOffset + index);将在原始list中移除
remove方法
public E remove(int index) {
// 检查索引
rangeCheck(index);
checkForComodification();
// 原始ArrayList将删除一个元素
E result = parent.remove(parentOffset + index);
this.modCount = parent.modCount;
this.size--;
return result;
}
结论:
- 在操作sublist的添加、移除等方法的时候,原始list将会被修改
- sublist是一个list的视图
结语
本人深知水平有限,欢迎指正本文错误之处。