ArrayList源码解析

数组拷贝

ArrayList 底层拷贝数组方法:

System.arraycopy(Object src, int srcPos, Object dest, int destPos, int length)

将指定源数组中的数组从指定位置复制到目标数组的指定位置

add 方法

JDK 1.8及以后版本,在 new ArrayList<>() 的时候,是没有分配空间的。使用的是空数组

   public ArrayList() {
        // DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; 
    }

当我们第一次使用 add 方法时候,才会初始化数组,数组大小为10

    public boolean add(E e) {
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        elementData[size++] = e;
        return true;
    }
ensureCapacityInternal 方法是用来确保新增元素时能够放的进我们的数组的。

ensureCapacityInternal 是如何 ArrayList内部数组的容量足够用的呢?

    /**
        calculateCapacity: 返回添加一个元素后的数组长度
    */
    private void ensureCapacityInternal(int minCapacity) {
        ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
    }

    private static int calculateCapacity(Object[] elementData, int minCapacity) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { // 第一次添加
            return Math.max(DEFAULT_CAPACITY, minCapacity);    // 返回 10
        }
        return minCapacity;
    }
ensureExplicitCapacity 方法确保容量够用
    private void ensureExplicitCapacity(int minCapacity) {
        modCount++;

        // 判断容量是否够用
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);     // 数组扩容方法
    }
grow 方法:将数组容量扩大到原来的1.5倍,并且将原数组中的数据拷贝到新数组中
    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);
    }

add 方法总结:

第一次调用 add 方法时,ArrayList 中的数组初始化,初始化大小为10,然后将 元素添加到数组中。

以后再调用 add 方法时,先判断是否需要扩容?

如不需要扩容,则直接添加元素到末尾

如需要扩容,则先将容量扩大到原来的 1.5 倍,再将原数组中的数据拷贝到新数组中,最后将原始添加到数组中的末尾

注意了:

ArrayList 底层维护的动态数组是

transient Object[] elementData;

ArrayList 实际存储数据的大小是 size, 而不是 elementData 数组的长度

 private int size;

上面我们所说的将元素添加到末尾是指,将原始添加到 elementData[size] = e 


get 方法

用于获取指定位置上的元素

    public E get(int index) {
        rangeCheck(index);   // 检查获取元素的下标,如果大于 size,则抛出异常

        return elementData(index);
    }
    
    /**
        返回 elementData 数组中下标为 index的元素
    */
    E elementData(int index) {
        return (E) elementData[index];
    }

Set方法

用于替换指定位置的元素,并返回原位置上的元素返回

    public E set(int index, E element) {
        rangeCheck(index);

        E oldValue = elementData(index);
        elementData[index] = element;
        return oldValue;
    }

remove(int index) 方法

用于删除指定下标的元素,并将删除元素返回

    public E remove(int index) {
        rangeCheck(index);

        modCount++;
        E oldValue = elementData(index);  // 获取删除元素

        int numMoved = size - index - 1;  // 计算往前移动元素的个数
        if (numMoved > 0)
            System.arraycopy(elementData, index+1, elementData, index,
                             numMoved);    // index下标后面的元素往前移动一位
        elementData[--size] = null; // 清除数组中最后一个元素

        return oldValue;
    }

remove(Object o) 方法

作用是将指定对象从 list集合中删除,删除成功返回 true,删除失败返回false。

    /**
        数组遍历,找到要删除元素的下标,
        通过下标进行删除(调用 System.arraycopy 方法进行数组前移)
    */ 
    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;
    }

contains(Object o) 方法

用于判断元素是否在 List 集合中,如果在的话返回找到的第一个元素在集合中的位置下标,不在的话就返回 -1

    public boolean contains(Object o) {
        return indexOf(o) >= 0;
    }
    /**
        indexOf 方法:底层也是用 for 循环遍历挨个对比,返回找到的第一个元素下标
    */
    public int indexOf(Object o) {
        if (o == null) {
            for (int i = 0; i < size; i++)
                if (elementData[i]==null)
                    return i;
        } else {
            for (int i = 0; i < size; i++)
                if (o.equals(elementData[i]))
                    return i;
        }
        return -1;
    }

toArray() 方法

作用是将集合转换为数组,通过源码发现它底层使用的也是 System.arraycopy 方法

    public Object[] toArray() {
        return Arrays.copyOf(elementData, size);
    }

addAll(Collection<? extends E> c) 方法

作用是往集合里边添加另一个集合,返回添加是否成功

    public boolean addAll(Collection<? extends E> c) {
        Object[] a = c.toArray();    // 1.将集合转换数组
        int numNew = a.length;       
        ensureCapacityInternal(size + numNew);  // 确保数组中能装的下集合中的元素
        System.arraycopy(a, 0, elementData, size, numNew);  // 将集合中元素拷贝到数组中
        size += numNew;             // ArrayList的实际存储大小
        return numNew != 0;
    }

forEach(Consumer<? super E> action) 方法

用来遍历 List 集合中的元素,传入参数是 Consumer接口的实现类。

    public void forEach(Consumer<? super E> action) {
        Objects.requireNonNull(action);
        final int expectedModCount = modCount;
        @SuppressWarnings("unchecked")
        final E[] elementData = (E[]) this.elementData;
        final int size = this.size;
        for (int i=0; modCount == expectedModCount && i < size; i++) {  // 遍历 集合中元素
            action.accept(elementData[i]);      // 调用accept 方法对每一个元素进行处理
        }
        if (modCount != expectedModCount) {
            throw new ConcurrentModificationException();
        }
    }

举例:打印集合中的元素

        ArrayList<String> list = new ArrayList<>();
        list.add("a1");
        list.add("a2");
        list.add("a3");
        list.add("a4");

        list.forEach(new Consumer<String>() {
            @Override
            public void accept(String s) {
                System.out.println(s);
            }
        });

sort(Comparator<? super E> c) 方法

用于对集合中元素进行排序,参数是Comparator 比较器接口。

    public void sort(Comparator<? super E> c) {
        final int expectedModCount = modCount;
        Arrays.sort((E[]) elementData, 0, size, c);
        if (modCount != expectedModCount) {
            throw new ConcurrentModificationException();
        }
        modCount++;
    }

举例:

        ArrayList<String> list = new ArrayList<>();
        list.add("a31");
        list.add("a33");
        list.add("a1");
        list.add("a17");

        list.sort(new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                return o1.compareTo(o2);
            }
        });
        list.forEach((s) -> {
            System.out.println(s);
        });

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值