ArrayList基本属性
// 当创建ArrayList时不指定初始容量,第一次添加数组时将elementData扩容为默认的10
private static final int DEFAULT_CAPACITY = 10;
//默认空数组
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
// 存放数据的数组
transient Object[] elementData;
//elementData数组中元素个数
private int size;
//数组发生size更改的次数,用于标识在迭代过程中不能修改集合,在迭代开始生成Iterator时会赋值int expectedModCount = modCount;每次next()迭代元素时就会检查 expectedModCount 和modCount是否相等,不等则抛ConcurrentModificationException异常,
//比如迭代中remove(),remove时modCount+1,下次next时检测到不相等则抛异常了
protected transient int modCount = 0;
//当创建ArrayList时不指定初始容量,使用默认的空数组
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
添加逻辑(下面都以创建ArrayList时不指定初始容量,且第一次添加新元素为例说明)
//添加元素
public boolean add(E e) {
modCount++;
add(e, elementData, size);
return true;
}
private void add(E e, Object[] elementData, int s) {
//1.若size==数组个数,出现这种相等有两种情况
//1.1 数组不为空且此时数组满了
//1.2 当创建ArrayList时不指定初始容量时,首次添加元素时size:0=数组个数:0
if (s == elementData.length)
//2.扩容
elementData = grow();
//3.数组默认添加新元素
elementData[s] = e;
//4.size+1
size = s + 1;
}
扩容逻辑
//扩容后数组大小=旧数组大小+(旧数组大小)>> 1
private Object[] grow() {
return grow(size + 1);
}
//扩容数组
private Object[] grow(int minCapacity) {
return elementData = Arrays.copyOf(elementData,
newCapacity(minCapacity));
}
//返回扩容后新数组大小,扩容后大小=原来大小的1.5倍左右,若旧数组为空,返回默认大小10
private int newCapacity(int minCapacity) {
// overflow-conscious code
//1.数组旧大小为0
int oldCapacity = elementData.length;
//2.数组新大小为=旧大小+旧大小带符号右移1位,即新大小=旧大小+旧大小一半,即扩容原来的一半取整
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity <= 0) {
//0 = 0 + 0>>1
//3.新大小=旧大小,出现这种情况只有:创建ArrayList时不指定初始容量时,且第一次添加新元素,返回默认数组大小10
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
return Math.max(DEFAULT_CAPACITY, minCapacity);
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return minCapacity;
}
//4.MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8,若扩容后大小 <= Integer最大值,返回扩容后大小
return (newCapacity - MAX_ARRAY_SIZE <= 0)
? newCapacity
: hugeCapacity(minCapacity);
}
//当源数组大小+1 大于 Integer.MAX_VALUE - 8,扩容后大小变为Integer.MAX_VALUE,
//否则扩容后大小变为Integer.MAX_VALUE - 8
//https://blog.youkuaiyun.com/weixin_42462804/article/details/108726206
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE)
? Integer.MAX_VALUE
: MAX_ARRAY_SIZE;
}
扩容后旧值复制到新数组中
# Arrays.copyOf
public static <T> T[] copyOf(T[] original, int newLength) {
return (T[]) copyOf(original, newLength, original.getClass());
}
@HotSpotIntrinsicCandidate
public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {
@SuppressWarnings("unchecked")
T[] copy = ((Object)newType == (Object)Object[].class)
? (T[]) new Object[newLength]
: (T[]) Array.newInstance(newType.getComponentType(), newLength);
System.arraycopy(original, 0, copy, 0,
Math.min(original.length, newLength));
return copy;
}
# System.arraycopy
//调用native方法实现真正的复制,src:源数组,srcPos:从哪个索引开始复制,dest:扩容后的空数组,destPos:从dest的哪个索引开始设值,length:复制元素个数
@HotSpotIntrinsicCandidate
public static native void arraycopy(Object src, int srcPos,
Object dest, int destPos,
int length);
在jdk9之前,添加代码是这样的:
public boolean add(E e) {
//1.扩容
ensureCapacityInternal(size + 1); // Increments modCount!!
//2.设置元素(直接用的size变量,此时size可能被其它线程改变,而8之后读取的add方法之前的size放到s中,在add时s不会变其它线程改变)
elementData[size++] = e;
return true;
}