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方法对数组进行扩容和删除元素

 

posted @ 2021-01-01 00:00  小_Leo  阅读(438)  评论(0)    收藏  举报