ArrayList原理解析

数组:效率高,但是其容量固定且无法动态改变。

ArrayList:容量可动态增长,但效率不如数组。

ArrayList定义:能够顺序的存储元素,可以存null值,动态的调整容量,对元素进行排序等一系列操作,线程不安全。

宏观说ArrayList是基于动态数组实现的。

构造函数:

private static final long serialVersionUID = 8683452581122892189L;

    /**
     * Default initial capacity.
     */
    private static final int DEFAULT_CAPACITY = 10;//默认的存储容量
    /**
     * Shared empty array instance used for empty instances.
     */
    private static final Object[] EMPTY_ELEMENTDATA = {};//空元素数组

    /**
     * The array buffer into which the elements of the ArrayList are stored.
     * The capacity of the ArrayList is the length of this array buffer. Any
     * empty ArrayList with elementData == EMPTY_ELEMENTDATA will be expanded to
     * DEFAULT_CAPACITY when the first element is added.
     *
     * Package private to allow access from java.util.Collections.
     */
    transient Object[] elementData;//存储元素的数组,定义了transient在实现Serializable序列化是,不会被串行话

    /**
     * The size of the ArrayList (the number of elements it contains).
     *
     * @serial
     */
    private int size;//ArrayList的元素数量 默认初始化为0,存在堆内存中,实际是ArrayList元素的个数

构造方法:

 public ArrayList(int initialCapacity) {//构造一个含有初始容量的ArrayList
        super();
        if (initialCapacity < 0)
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        this.elementData = new Object[initialCapacity];//初始化一个initialCapacity大小的数组
    }

    /**
     * Constructs an empty list with an initial capacity of ten.
     */
    public ArrayList() {
        super();//默认创建10个大小数组
        this.elementData = EMPTY_ELEMENTDATA;//将elementData的引用指向定义的空数组 
    }

    /**
     * Constructs a list containing the elements of the specified
     * collection, in the order they are returned by the collection's
     * iterator.
     *
     * @param c the collection whose elements are to be placed into this list
     * @throws NullPointerException if the specified collection is null
     */
    public ArrayList(Collection<? extends E> c) {
        elementData = c.toArray();
        size = elementData.length;
        // c.toArray might (incorrectly) not return Object[] (see 6260652)
        if (elementData.getClass() != Object[].class)//返回若不是Object[]将调用Arrays.copyOf方法将其转为Object[]
            elementData = Arrays.copyOf(elementData, size, Object[].class);//扩容
    }
动态增加容量

当添加元素的时候第一步就是先检查时候扩容,

 public void ensureCapacity(int minCapacity) {
        int minExpand = (elementData != EMPTY_ELEMENTDATA)
            // any size if real element table
            ? 0
            // larger than default for empty table. It's already supposed to be
            // at default size.
            : DEFAULT_CAPACITY;

        if (minCapacity > minExpand) {
            ensureExplicitCapacity(minCapacity);
        }
    }
//确认所需要的最小容量,在没有初始化的情况下,会使用默认容量为最小容量
    private void ensureCapacityInternal(int minCapacity) {
        if (elementData == EMPTY_ELEMENTDATA) {
            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
        }

        ensureExplicitCapacity(minCapacity);
    }

    private void ensureExplicitCapacity(int minCapacity) {
        modCount++;//如果确定要扩容,会修改modCount

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

grow()方法

 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);//用计算出来的数组长度,往下传继续处理
    }

copyOf()方法

 public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {
        T[] copy = ((Object)newType == (Object)Object[].class)
            ? (T[]) new Object[newLength]//用新的长度创建一个新的数组
            : (T[]) Array.newInstance(newType.getComponentType(), newLength);
        System.arraycopy(original, 0, copy, 0,//把原数组里的元素拷进新数组里并返回
                         Math.min(original.length, newLength));
        return copy;
    }

总结:

在添加时候无论是add还是addAll,都是先判断时候要扩容,若果需要扩容,就复制数组,设置对应下标元素。

在扩容的时候,默认扩容一半,不够的话就用目标的size作为扩容后的容量。

在扩容后,修改modCount

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值