ArrayList简介及部分源码分析

1.ArrayList介绍

ArrayList的底层是数组队列,相当于动态数组。与 Java 中的数组相比,它的容量能动态增长。在添加大量元素前,应用程序可以使用ensureCapacity操作来增加 ArrayList实例的容量。这可以减少递增式再分配的数量。
ArrayList继承了AbstractList,实现了 List, RandomAccess, Cloneable, java.io.Serializable
接口

特点

  • Object[] 数组实现,默认大小为 10 ,支持随机访问,连续内存空间,
  • 插入末尾时间复杂度 o(1),插入第 i 个位置时间复杂度 o(n - i)。(插入效率受插入位置影响)
  • 扩容,大小变为 1.5 倍,调用Arrays.copyOf(底层 System.ArrayCopy),复制到新数组,指针指向新数组。(浅拷贝)不可指定扩容增长因子
  • 线程不安全


1.1ArrayList与Vector的区别

  1. ArrayList是 List 的主要实现类,底层使用 Object[ ]存储,适用于频繁的查找工作,线程不安全 ;
  2. Vector 是 List 的古老实现类,底层使用 Object[ ]存储,线程安全的。

1.2ArrayList与LinkedList对比

1.线程安全问题

ArrayListLinkedList都是线程不安全的

2.底层数据结构

ArrayList底层使用的是Object存储元素,而LinkedList底层使用的是双向链表

3.插入删除是否受元素位置影响

ArrayList

ArrayList在执行默认插入方法add(E e)时会默认将待插入元素追加到数组末尾,时间复杂度为O(1),而要在指定位置插入元素add(index i,E e)就会受到元素位置影响 时间复杂度就为 O(n-i),因为要进行后续元素移位操作

LinkedList

LinkedList使用链表存储元素,所以使用默认插入方法add(E e)时间复杂度为O(1),而要在指定位置插入元素add(index i,E e)则需要的时间复杂度为O(n),因为需要遍历到目标位置再进行插入

4.是否支持快速随机访问(下标访问)

ArrayList支持快速随机访问,而LinkedList不支持快速随机访问

5.内存空间占用

ArrayList空间浪费主要体现在扩容后数组尾部会产生一定量的空节点
LinkedList的空间浪费主要体现在每个节点都会占用较大的内存空间

2.核心源码

源码构造函数

/**
     * Constructs an empty list with the specified initial capacity.
     *
     *
     * @param  initialCapacity  the initial capacity of the list
     * @throws IllegalArgumentException if the specified initial capacity
     *         is negative
     *
     *
     *  带初始容量参数的构造函数
     */
    public ArrayList(int initialCapacity) {
        if (initialCapacity > 0) {  //如果传入的参数大于0,创建initialCapacity大小的数组
            this.elementData = new Object[initialCapacity];
        } else if (initialCapacity == 0) {  //等于0则取出空数组
            this.elementData = EMPTY_ELEMENTDATA;
       
       
       
        } else { //小于0则抛出异常
            throw new IllegalArgumentException("Illegal Capacity: "+
                    initialCapacity);
        }
    }

    /**
     * Constructs an empty list with an initial capacity of ten.
     * //默认的无参构造
     * //集合创建时为空数组DEFAULTCAPACITY_EMPTY_ELEMENTDATA长度为0,当第一个元素添加后扩容为10
     */
    public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_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
     *
     * 带有集合参数的构造,构造一个包含指定集合元素的ArrayList,顺序为参数集合的迭代器返回顺序
     * 因为其中含有对参数的函数调用,所以可能会抛出空指针异常
     */
    public ArrayList(Collection<? extends E> c) {
        //集合转为数组
        Object[] a = c.toArray();
        if ((size = a.length) != 0) {//如果数组长度不为0
            if (c.getClass() == ArrayList.class) {
                //如果参数c为类型ArrayList就直接将参数集合数组赋给ArrayList元素数组
                elementData = a;
            } else {//c为其他类型
                //将a数组拷贝给elementData数组
                elementData = Arrays.copyOf(a, size, Object[].class);
            }
        } else {//数组长度为0
            // 将空数组赋给elementdata元素数组
            // replace with empty array.
            elementData = EMPTY_ELEMENTDATA;
        }
    }

在执行无参构造arrayList时,是初始化赋值了一个空数组,只有当真正的元素添加后才真正分配容量

扩容核心方法

    /**
     * Increases the capacity of this <tt>ArrayList</tt> instance, if
     * necessary, to ensure that it can hold at least the number of elements
     * specified by the minimum capacity argument.
     *
     * @param   minCapacity   the desired minimum capacity 所需最小容量
     *
     */
    public void ensureCapacity(int minCapacity) {
        int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
            // any size if not default element table
            ? 0
            // larger than default for default empty table. It's already
            // supposed to be at default size.
            : DEFAULT_CAPACITY;

        if (minCapacity > minExpand) {
            //如果最小容量大于已有的最大容量
            //判断是否需要扩容
            ensureExplicitCapacity(minCapacity);
        }
    }

    //计算容量
    private static int calculateCapacity(Object[] elementData, int minCapacity) {

        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            //如果elementData为空返回默认扩容量或最小需求量的最大值
            return Math.max(DEFAULT_CAPACITY, minCapacity);
        }
        //不为空返回最小需求量
        return minCapacity;
    }

    //作为扩容功能入口
    private void ensureCapacityInternal(int minCapacity) {
        ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
    }
    //判断是否需要扩容
    private void ensureExplicitCapacity(int minCapacity) {
        modCount++;

        // overflow-conscious code
        if (minCapacity - elementData.length > 0) //最小需要量大于数组长度(需要扩容)
            //调用grow方法进行扩容,调用此方法代表已经开始扩容了
            grow(minCapacity);
    }

    /**
     * The maximum size of array to allocate.
     * Some VMs reserve some header words in an array.
     * Attempts to allocate larger arrays may result in
     * OutOfMemoryError: Requested array size exceeds VM limit
     */
    //要分配数组的最大的大小
    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
     */

    //扩容核心方法
    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);  //若大于调用hugeCapacity获取新容量


        // minCapacity is usually close to size, so this is a win:

        //拷贝数组
        elementData = Arrays.copyOf(elementData, newCapacity);
    }

    private static int hugeCapacity(int minCapacity) {
        if (minCapacity < 0) // overflow  最小需要量为负导致数据溢出 抛出异常
            throw new OutOfMemoryError();
        return (minCapacity > MAX_ARRAY_SIZE) ?  //如果minCapacity大于MAX_ARRAY_SIZE,
                                                 // 则新容量则为Interger.MAX_VALUE,
                                                    // 否则,新容量大小则为 MAX_ARRAY_SIZE。
            Integer.MAX_VALUE :
            MAX_ARRAY_SIZE;
    }

ensureCapacit方法

/**
     * Increases the capacity of this <tt>ArrayList</tt> instance, if
     * necessary, to ensure that it can hold at least the number of elements
     * specified by the minimum capacity argument.
     *
     * @param   minCapacity   the desired minimum capacity 所需最小容量
     *
     */
    public void ensureCapacity(int minCapacity) {
        int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
            // any size if not default element table
            ? 0
            // larger than default for default empty table. It's already
            // supposed to be at default size.
            : DEFAULT_CAPACITY;

        if (minCapacity > minExpand) {
            //如果最小容量大于已有的最大容量
            //判断是否需要扩容
            ensureExplicitCapacity(minCapacity);
        }
    }

ensureCapacitArrayList内部没有被调用过,所以这属于一个供用户调用的接口,作用是用户在大量元素添加之前,调用此方法预先扩容到近似容量以减少重新分配扩容的次数

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值