ArrayList源码阅读笔记
内部属性
//默认容量
private static final int DEFAULT_CAPACITY = 10;
//对于已知大小为0 的 返回此空数组
private static final Object[] EMPTY_ELEMENTDATA = {};
//默认容量DEFAULT_CAPACITY的空数组 , 暂时实际为0 的空数组 ,初次执行add方法时,会扩容为DEFAULT_CAPACITY
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
//存放数据的数组的缓存变量,不可序列化
transient Object[] elementData;
//元素数量
private int size;
//父级AbstractList的成员属性:用于记录集合结构变化次数(扩容、删除、新增等所有会改变集合长度的操作)
protected transient int modCount = 0;
构造方法
1、public ArrayList(int initialCapacity) :
根据给定大小,初始化elementData ;
如果大小为0 ,设置 elementData = EMPTY_ELEMENTDATA 空数组
2、public ArrayList() :
设置 elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA空数组,
初次执行add()时会被扩容为默认大小
3、public ArrayList(Collection<? extends E> c) :
c不能为null,c长度为0 ,设置elementData = EMPTY_ELEMENTDATA 空数组 ,
否则elementData 长度为c的大小
增删改查
add : 新增
1、如果是指定索引新增:检查索引 rangeCheckForAdd(int index)
2、判断是否需要扩容 (当前集合元素个数+1,作为最小参数)
3、添加元素
set : 修改
1、检查索引 rangeCheck(index);
2、修改
remove: 删除
1、根据索引删除 : 检查索引 rangeCheck(index);
2、删除
get : 查看
1、检查索引 rangeCheck(index);
2、返回元素
扩容机制
1、根据当前集合实际元素siez + 1 作为集合需要的最小容量值,判断是否需要扩容 【应为只有add 才会有扩容,所以需要用size+1判断本次新增是否需要扩容】
2、 ensureCapacityInternal:确定内部需要容量最小值
private void ensureCapacityInternal(int minCapacity) {
//初次执行add 无参构造容量设置为默认容量
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
ensureExplicitCapacity(minCapacity);
}
3、:ensureExplicitCapacity-确保容量
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
//所需最小容量 大于 当前elementData长度 执行扩容
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
4、执行扩容:
private void grow(int minCapacity) {
int oldCapacity = elementData.length;
// 扩容 1.5倍
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity < 0) //扩容1.5倍后,新容量 小于 所需最小容量 ,使用最小容量为扩容后大小
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0) //扩容1.5倍后,新容量超过数组支持的最大容量值,使用最大值
newCapacity = hugeCapacity(minCapacity);
elementData = Arrays.copyOf(elementData, newCapacity);//拷贝数据到一个新的容量大小的数组中
}
遍历
foreach 使用了modCount结构变化次数验证,遍历过程中改变size操作会报ConcurrentModificationException
public void forEach(Consumer<? super E> action) {
Objects.requireNonNull(action);
final int expectedModCount = modCount;
@SuppressWarnings("unchecked")
final E[] elementData = (E[]) this.elementData;
final int size = this.size;
for (int i=0; modCount == expectedModCount && i < size; i++) {
action.accept(elementData[i]);
}
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
}
Iterator:内部类Itr迭代器 remove方法显示的设置modCount跟操作后相等,所以支持迭代过程中修改
private class Itr implements Iterator<E> {
public void remove() {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();
try {
ArrayList.this.remove(lastRet);
cursor = lastRet;
lastRet = -1;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
}
序列化 序列化后的流中记录了集合结构变化次数,所以读操作后在修改,也会发现
读 :readObject
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
elementData = EMPTY_ELEMENTDATA;
// Read in size, and any hidden stuff
s.defaultReadObject();
// Read in capacity
s.readInt(); // ignored
if (size > 0) {
// be like clone(), allocate array based upon size not capacity
ensureCapacityInternal(size);
Object[] a = elementData;
// Read in all elements in the proper order.
for (int i=0; i<size; i++) {
a[i] = s.readObject();
}
}
}
写 :writeObject
private void writeObject(java.io.ObjectOutputStream s)
throws java.io.IOException{
// Write out element count, and any hidden stuff
int expectedModCount = modCount;
s.defaultWriteObject();
// Write out size as capacity for behavioural compatibility with clone()
s.writeInt(size);
// Write out all elements in the proper正确的 order.
for (int i=0; i<size; i++) {
s.writeObject(elementData[i]);
}
//写的过程中,集合结构被改变,会报错
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
}