ArrayList源码分析

概述

该集合是我们实际工作中最常见的集合,他不支持线程安全的操作,支持随机访问(在单线程下对指定索引位的元素读取操作的时间为O(1)。

集合的底层实现是一个数组,容器存储元素的个数不能多于数组的当前容量;size(), isEmpty(), get(), set()方法均能在常数时间内完成;add()方法的时间开销跟插入位置有关

自动扩容机制

每当向集合中添加元素时,集合都会去检查添加元素后,当前集合元素的个数是否会超出当前数组的产的高度,如果超出长度,数组将会进行扩容。

数组在进行扩容时,每次扩容大概会增长为原数组容量的1.5倍;这种操作的代价是很高的,因此在实际应用中,我们应该尽量避免数组容量的扩张,能预计要保存元素的数量时,在构造集合时,就指定其容量。或者根据实际需求,通过调用ensureCapacity方法来手动增加容量。

部分重要源码翻译

package com.zyh.list;

import java.io.Serializable;
import java.util.Arrays;
import java.util.Collection;

/**
 * @BelongsProject:Java
 * @Author:zhangyuhang
 * @CreateTime:2022-09-14 21:25
 * @Description:TODO
 * @Version:1.0
 */
public class ArrayList<E> extends AbstractList<E> implements List<E>,RandomAccess, Serializable {

    /**
     * 该常量表示集合默认的初始化容量
     * 在使用默认的构造方法的情况下,只出现在ArrayList第一个确定容量时
     */
    private static final int DEFAULT_CAPACITY = 10;

    /**
     * 该常量会在初始化集合时使用,用于将elementData数组初始化为一个空数组
     */
    private static final Object[] EMPTY_ELEMENTDATA = {};

    /**
     * 该常量会在集合第一次添加数据时使用
     * 在默认情况下用作于集合第一次扩容的判断依据
     */
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

    /**
     * transient 关键字修饰的成员变量不是该对象序列化的一部分
     * 该对象主要用于存储集合中各个数据对象的引用
     * non-private to simplify nested class access
     */
    transient Object[] elementData;

    /**
     * 记录当前集合的容量
     */
    private int size;


    /**
     * 为集合设置一个指定的初始化容量
     * @param initialCapacity 容量
     */
    public ArrayList(int initialCapacity) {
        if (initialCapacity > 0) {
            this.elementData = new Object[initialCapacity];
        } else if (initialCapacity == 0) {
            this.elementData = EMPTY_ELEMENTDATA;
        } else {
            throw new IllegalArgumentException("Illegal Capacity: "+
                    initialCapacity);
        }
    }

    /**
     * 初始化一个默认容量为0 的集合
     */
    public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }

    /**
     * 参照一个集合进行初始化
     * @param c
     */
    public ArrayList(Collection<? extends E> c) {
        Object[] a = c.toArray();
        if ((size = a.length) != 0) {
            if (c.getClass() == java.util.ArrayList.class) {
                elementData = a;
            } else {
                elementData = Arrays.copyOf(a, size, Object[].class);
            }
        } else {
            // replace with empty array.
            elementData = EMPTY_ELEMENTDATA;
        }
    }

    /**
     * 向集合中新增一个对象
     * @param e
     * @return
     */
    public boolean add(E e) {
        // Increments modCount!!
        ensureCapacityInternal(size + 1);
        elementData[size++] = e;
        return true;
    }

    /**
     * 如果集合需要扩容,则执行扩容操作
     * @param minCapacity 容量
     */
    private void ensureCapacityInternal(int minCapacity) {
        ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
    }

    /**
     * 计算集合的容量值
     * @param elementData 数组
     * @param minCapacity 容量
     * @return 容量
     */
    private static int calculateCapacity(Object[] elementData, int minCapacity) {
        //如果集合是空集合
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            //返回默认容量和传入容量的大值
            return Math.max(DEFAULT_CAPACITY, minCapacity);
        }
        //如果不是空集合,直接返回传入的值
        return minCapacity;
    }

    /**
     * 如果传入容量大于 数组的长度则扩容
     * @param minCapacity 容量
     */
    private void ensureExplicitCapacity(int minCapacity) {
        modCount++;

        // overflow-conscious code
        if (minCapacity - elementData.length > 0) {
            grow(minCapacity);
        }
    }


    /**
     * 数组的最大长度
     */
    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

    /**
     * 集合扩容方法
     * @param 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);
    }

    /**
     * 用于防止扩容计算的容量大于数组的最大容量
     * @param minCapacity 容量
     * @return 容量
     */
    private static int hugeCapacity(int minCapacity) {
        // overflow
        if (minCapacity < 0)
        {
            throw new OutOfMemoryError();
        }
        return (minCapacity > MAX_ARRAY_SIZE) ?
                Integer.MAX_VALUE :
                MAX_ARRAY_SIZE;
    }


    /**
     * 将元素添加到集合指定索引处,指定索引及后面的元素向后移动一位
     * @param index 索引
     * @param element 元素
     */
    public void add(int index, E element) {
        rangeCheckForAdd(index);
        // Increments modCount!!
        ensureCapacityInternal(size + 1);
        /**
         * elementData 要复制的源数组
         * index 从源数组中复制的起始位置
         * elementData 进行数组复制的目标数组
         * index + 1 在目标数组中复制的起始位置
         * size - index 指定进行复制的长度(指定索引后面的元素)
         */
        System.arraycopy(elementData, index, elementData, index + 1,
                size - index);
        elementData[index] = element;
        size++;
    }

    /**
     * 判断指定索引是否正常
     * @param index
     */
    private void rangeCheckForAdd(int index) {
        if (index > size || index < 0) {
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
        }
    }

    /**
     * 指定索引错误提示
     * @param index
     * @return
     */
    private String outOfBoundsMsg(int index) {
        return "Index: "+index+", Size: "+size;
    }


    /**
     * 返回列表中指定索引处的元素
     *
     * @param index
     * @return
     */
    public E get(int index) {
        //验证索引是否正常
        rangeCheck(index);
        return elementData(index);
    }

    /**
     * 返回数组指定下标处的元素
     * @param index
     * @return
     */
    E elementData(int index) {
        return (E) elementData[index];
    }

    /**
     * 判断索引是否大于集合长度,大于则抛异常
     * @param index
     */
    private void rangeCheck(int index) {
        if (index >= size) {
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
        }
    }

    /**
     * 替换指定索引处的元素,并返回被替换的元素
     * @param index
     * @param element
     * @return
     */
    public E set(int index, E element) {
        rangeCheck(index);

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

    /**
     * 移除指定索引处的元素,并返回被移除的元素,指定索引后如果还存在元素,则向前移动
     * @param index
     * @return
     */
    public E remove(int index) {
        rangeCheck(index);

        modCount++;
        E oldValue = elementData(index);

        //被移除的索引后面剩余的元素个数
        int numMoved = size - index - 1;
        if (numMoved > 0) {
            /**
             * elementData 拷贝的源数组
             * index+1   从源数组拷贝的起始位置
             * elementData 拷贝的目标数组
             * index 拷贝到目标数组的起始位置
             * numMoved 从源数组拷贝的长度
             */
            System.arraycopy(elementData, index+1, elementData, index,
                    numMoved);
        }
        // 将最后一个元素置空
        elementData[--size] = null;

        return oldValue;
    }


    /**
     * 根据指定元素移除
     * @param o
     * @return
     */
    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;
    }


    /**
     * 跳过边界检查且不返回已删除值的私有删除方法
     * @param index
     */
    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;
    }

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值