ArrayList.add()方法源码分析
add方法的用途
1.在ArrayList末尾插入元素
2.在ArrayList中间插入元素
在ArrayList末尾插入元素
调用add方法会先调用ensureCapacityInternal()方法判断数组是否需要扩容
public boolean add(E e) { ensureCapacityInternal(size + 1); // Increments modCount!! elementData[size++] = e; return true; }
ensureCapacityInternal(int minCapacity)
判断数组是否需要扩容
通过calculateCapacity方法判断数组是否为空
private void ensureCapacityInternal(int minCapacity) { ensureExplicitCapacity(calculateCapacity(elementData, minCapacity)); }
calculateCapacity(object[] elementData , int minCapacity)
判断数组是否为空
如果数组为空则返回默认的数组长度 10( DEFAULT_CAPACITY = 10)
如果数组不为空则返回传入参数minCapacity
private static int calculateCapacity(Object[] elementData, int minCapacity) { if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { return Math.max(DEFAULT_CAPACITY, minCapacity); } return minCapacity; }
ensureExplicitCapacity(int minCapacity)
首先使数组变化次数+1(modCount++)
判断如果传入的数组长度
如果传入长度比原数组的长度长则调用grow()方法扩容
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
grow()
oldCapacity 当前数组得容量
newCapacity 新数组容量为当前数组长度的1.5倍(>>唯一运算符 >>1相当于除2)
如果 新数组容量-传入数组容量则赋值
当第一次使用add方法时minCapacity=10 , oldCapacity=0 , newCapacity=0这时需要对数组容量进行扩容
当数组扩容后容量(newCapacity)大于数组得最大容量(MAX_ARRAY_SIZE=Integet.MAX_VALUE-8=-231-8)时将数组扩容至最大(基本用不上)
使用Arrays.copyOf()方法将数组扩容并布置给当前数组
private void grow(int minCapacity) { // overflow-conscious code int oldCapacity = elementData.length; int newCapacity = oldCapacity + (oldCapacity >> 1); if (newCapacity - minCapacity < 0) newCapacity = minCapacity; if (newCapacity - MAX_ARRAY_SIZE > 0) newCapacity = hugeCapacity(minCapacity); // minCapacity is usually close to size, so this is a win: elementData = Arrays.copyOf(elementData, newCapacity); } 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中间插入元素
public void add(int index, E element) { rangeCheckForAdd(index); ensureCapacityInternal(size + 1); // Increments modCount!! System.arraycopy(elementData, index, elementData, index + 1, size - index); elementData[index] = element; size++; }
使用rangeCheckForAdd()方法判断需要插入的位置是否合法
private void rangeCheckForAdd(int index) {
if (index > size || index < 0)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
使用ensureCapacityInternal(int minCapacity)方法判断需要插入的位置并可能对数组扩容
private void ensureCapacityInternal(int minCapacity) { ensureExplicitCapacity(calculateCapacity(elementData, minCapacity)); }
使用System.arraycopy(Object src , int srcPros , Object dest , int destPos , int length)方法对数组进行复制 , 并将需要插入的位置空出
arraycopy(Object src , int srcPros , Object dest , int destPos , int length)目的是将一个数组得一部分传入另一个数组的指定位置
native修饰的方法底层使用C或C++编写
elementData既是传入的源数组也是需要被插入的目标数组
index控制拷贝开始的位置
index+1表示拷贝到elementData中index+1的位置
即从第index位开始拷贝 , 拷贝到原数组index+1的位置
size-index表示从index位开始后方一共有多少位需要被复制
当arraycopy方法执行结束之后elementData数组从第index位开始到结束的所有位置都依次向后移动了一位 , 此时第index位为空 , 即需要插入的位置为空
public static native void arraycopy(Object src, int srcPos,Object dest, int destPos,int length);
System.arraycopy(elementData, index, elementData, index + 1, size - index);
将需要插入的元素赋值给数组得第index位
将数组中非空元素的数量+1
elementData[index] = element;
size++;
总结
add方法中的方法嵌套使得理解挺吃力需要在多看几遍
可以通过arrarcopy方法对数组进行扩容和删除元素