【源码】ArrayList源码

前言

作为最常用的集合之一,有必要读一下源码
ArrayList,基于数组实现,因此元素的读取速度十分快,因为数组在内存的上地址连续,但是插入删除涉及到数组元素的移动,因此效率较低。

构造方法

	// 空(默认)构造方法
	public ArrayList() {
        super();
        this.elementData = EMPTY_ELEMENTDATA;
    }

	// 存储数据的数组
	transient Object[] elementData;
	// 默认初始化的空数组
	private static final Object[] EMPTY_ELEMENTDATA = {};
	// 接受集合参数构造,赋值size并将参数集合copy到存储数组
	public ArrayList(Collection<? extends E> c) {
        elementData = c.toArray();
        size = elementData.length;
        if (elementData.getClass() != Object[].class)
            elementData = Arrays.copyOf(elementData, size, Object[].class);
    }

构造方法比较简单,我们平时最常用的默认构造,初始化内部数组为空数组。

add插入元素

	public boolean add(E e) {
        ensureCapacityInternal(size + 1);
        elementData[size++] = e;
        return true;
    }

	private void ensureCapacityInternal(int minCapacity) {
        // 发现如果初始化为空,则默认扩容至10
        if (elementData == EMPTY_ELEMENTDATA) {
            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
        }

        ensureExplicitCapacity(minCapacity);
    }
    
	private static final int DEFAULT_CAPACITY = 10;
    
	private void ensureExplicitCapacity(int minCapacity) {
        modCount++;

        // 预计容量大于当前容量则进行扩容
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }

	private void grow(int minCapacity) {
        // 旧容量
        int oldCapacity = elementData.length;
        // 位运算
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        // 容量校验
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);

		// 复制
        elementData = Arrays.copyOf(elementData, newCapacity);
    }

	// 指定位置插入
	public void add(int index, E element) {
		// 检查下标是否越界
        rangeCheckForAdd(index);

		// 同上
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        // native方法
        System.arraycopy(elementData, index, elementData, index + 1,
                         size - index);

		// 复制,长度+1
        elementData[index] = element;
        size++;
    }

插入元素第一件事就是根据插入后的长度判断是否需要扩容,由于默认构造为空数组,因此第一次插入会发生一次扩容。在指定位置的元素插入会涉及整个元素的移动,因此调用的是native方法,效率较高。

get(int index)获取元素

	public E get(int index) {
		// 检查数组下标 
        rangeCheck(index);
		
		// return elementData[index]
        return elementData(index);
    }

contains(Object o)判断元素是否存在

	public boolean contains(Object o) {
        return indexOf(o) >= 0;
    }

remove(int index)根据下标移除元素

	public E remove(int index) {
		// 检查下标
        rangeCheck(index);
		// 修改数+1
        modCount++;
        // 取出要移除的元素
        E oldValue = elementData(index);
		
		// 如果非最后一个元素,调用native方法复制数组
        int numMoved = size - index - 1;
        if (numMoved > 0)
            System.arraycopy(elementData, index+1, elementData, index,
                             numMoved);
                          
        // 如果是最后一个元素,直接将其指向null,等待GC回收
        elementData[--size] = null; 

		// 返回被移除的元素
        return oldValue;
    }

remove(Object o)移除元素

	// 遍历匹配后调用fastRemove(index)
	public boolean remove(Object o) {
        if (o == null) {
            for (int index = 0; index < size; index++)
                if (elementData[index] == null) {
                    fastRemove(index);
                    return true;
                }
        } else {
            for (int index = 0; index < size; index++)
                if (o.equals(elementData[index])) {
                    fastRemove(index);
                    return true;
                }
        }
        return false;
    }
    
	// fastRemove逻辑基本跟remove相同
	private void fastRemove(int index) {
        modCount++;
        int numMoved = size - index - 1;
        if (numMoved > 0)
            System.arraycopy(elementData, index+1, elementData, index, numMoved);
        elementData[--size] = null; 
    }

removeAll(Collection c)

	public boolean removeAll(Collection<?> c) {
        Objects.requireNonNull(c);
        return batchRemove(c, false);
    }

    // 一段比较巧妙的算法
	private boolean batchRemove(Collection<?> c, boolean complement) {
        final Object[] elementData = this.elementData;
        int r = 0, w = 0;
        boolean modified = false;
        try {
            for (; r < size; r++)
                if (c.contains(elementData[r]) == complement)
                    elementData[w++] = elementData[r];
        } finally {
            // 这个判断分支看不懂
            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;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值