ArrayLIst源码探究

一直知道ArrayList内部是使用数组实现的,但之前也只是大致扫过部分方法的源码,趁着刷剑指offer第二遍的空隙看一下源码,源码问题多次面试也都问到了。
ArrayList内部维持一个数组:

transient Object[] elementData;
private int size;

size保存ArrayList中的实际元素数量,size不一定等于elementData的长度,一般小于它,这个数组的初始容量为10。
那么ArrayList是如何保证实现动态改变数组容量的呢?在每次执行添加操作时,会先判断此时elementData数组是否有足够的的容量,若没有则扩展数组为原来的1.5倍,如下:

// 在指定位置插入元素
public void add(int index, E element) {
        rangeCheckForAdd(index);// 先检查索引是否有效

        ensureCapacityInternal(size + 1); // 保证数组大小
        System.arraycopy(elementData, index, elementData, index + 1, size - index);// 将数组指定索引后边元素向前移动
        elementData[index] = element;
        size++;
}
private void ensureCapacityInternal(int minCapacity) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
        }
        ensureExplicitCapacity(minCapacity);
    }
    // Explicit:明确的
    private void ensureExplicitCapacity(int minCapacity) {
        modCount++;
        // conscious:自觉地
        // overflow-conscious code
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }


    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
    /**
     * Increases the capacity to ensure that it can hold at least the
     * number of elements specified(指定) by the minimum capacity argument.
     *
     * @param minCapacity the desired minimum capacity
     */
    // 增长1.5倍
    private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity + (oldCapacity >> 1);// 1.5倍
        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);
    }

我感觉在源码里边这个地方设计的特别好(难理解),removeAll和retainAll调用了同一个方法batchRemove:

// 这是删除集合c存在ArrayList中的元素
public boolean removeAll(Collection<?> c) {
    Objects.requireNonNull(c);
    return batchRemove(c, false);
}
// retain:保留;保留集合c中的元素,其余删除
public boolean retainAll(Collection<?> c) {
    Objects.requireNonNull(c);
    return batchRemove(c, true);
}
private boolean batchRemove(Collection<?> c, boolean complement) {
        final Object[] elementData = this.elementData;
        int r = 0, w = 0;
        boolean modified = false;
        try {
            //精髓
            /*
                complement:true时保留集合c中的值,false时删除c中的值remove。
                当for循环结束时,符合要求的值被依次写入数组
            */
            for (; r < size; r++)
                if (c.contains(elementData[r]) == complement)
                    elementData[w++] = elementData[r];
        } finally {
            // Preserve behavioral compatibility with AbstractCollection,
            // even if c.contains() throws.
            if (r != size) {
                System.arraycopy(elementData, r,
                                 elementData, w,
                                 size - r);
                w += size - r;
            }
            // 数组有变化
            if (w != size) {
                // clear to let GC do its work
                for (int i = w; i < size; i++)
                    elementData[i] = null;
                modCount += size - w;
                size = w;
                modified = true;
            }
        }
        return modified;
}
  • 0
    点赞
  • 0
    评论
  • 0
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

打赏
文章很值,打赏犒劳作者一下
相关推荐
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页

打赏

cs-lrx

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者