ArrayList源码深入解析

最近在看《算法与数据结构Java版》这本书,正好看到第三章线性表,就顺便看了一下ArrayList和LinkedList的源码,深入的了解了他们之间的区别和性能方面的优缺点。先单独说一下ArrayList的实现原理。

概要

ArrayList的实现原理其实就是数组,它是线程不安全的,允许其中元素为null。
它实现了 List<E>, RandomAccess, Cloneable, java.io.Serializable接口,
其中RandomAccess代表了其拥有随机快速访问的能力,ArrayList可以以O(1)的时间复杂度去根据下标访问元素。

因为其底层结构是数组,所以它是占据了一块连续的内存空间,其长度就是数组的大小,因此它有数组的缺点,空间效率不高,但是也有优点,就是查询速度快,时间效率很高

当集合中的元素超出数组的长度是,数组就会进行扩容操作,扩容操作是ArrayList存储操作缓慢的主要原因,尤其是当数据量越来越大,每次扩容消耗的时间会越来越多。

所以如果我们事先预知数据量的大小,可以通过public ArrayList(int initialCapacity) {}构造方法来指定集合的大小,以减少扩容次数,提高写入效率

构造方法详解

    //集合的初始容量为10
    private static final int DEFAULT_CAPACITY = 10;
    //默认构造函数里的空数组
    private static final Object[] EMPTY_ELEMENTDATA = {
    };
    //真正存放元素的数组
    private transient Object[] elementData;
    //自定义初始容量的构造方法
    public ArrayList(int initialCapacity) {
    
        super();
        //如果初始容量小于0则报IllegalArgumentException异常
        if (initialCapacity < 0)
            throw new IllegalArgumentException("Illegal Capacity: " + initialCapacity);
        this.elementData = new Object[initialCapacity];
    }
    //默认的构造方法
    public ArrayList() {
    
        super();
        //默认的构造方法是将空数组赋值给了elementData
        this.elementData = EMPTY_ELEMENTDATA;
    }
    //将别的集合直接赋值进行创建的构造方法
    public ArrayList(Collection<? extends E> c) {
    
        //直接用toArray()的方法获取集合的数组对象,并且直接赋值给elementData
        elementData = c.toArray();
        size = elementData.length;
        // 这里是当c.toArray出错,没有返回Object[]时,利用Arrays.copyOf 来复制集合c中的元素到elementData数组中
        if (elementData.getClass() != Object[].class)
            elementData = Arrays.copyOf(elementData, size, Object[].class);
    }

调用构造方法后,会构造出数组elementData和集合大小size。

常用API详解

1 添加元素

每次添加元素之前都会判断添加后的容量是否需要扩容。
    //添加单个元素
    public boolean add(E e) {
    
        //判断添加后的长度是否需要扩容
        ensureCapacityInternal(size + 1); 
        //在数组末尾添加上当前元素,并且修改size大小
        elementData[size++] = e;
        return true;
    }
    //集合的初始容量为10
    private static final int DEFAULT_CAPACITY = 10;
    //判断是否是第一次初始化数组
    private void ensureCapacityInternal(int minCapacity) {
    
        //判断当前数组是否 == EMPTY_ELEMENTDATA,因为默认构造函数创建时是将空数组EMPTY_ELEMENTDATA赋值给elementData
        if (elementData == EMPTY_ELEMENTDATA) {
    
            //判断默认容量10和当前数据长度的大小,取其中大的值作为判断本次是否需要扩容的依据,由于第一次数组是空的,所以默认要使数组扩容到10的长度
            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
        }
        //判断是否需要扩容
        ensureExplicitCapacity(minCapacity);
    }
    //判断扩容的方法
    private void ensureExplicitCapacity(int minCapacity) {
    
        //如果需要扩容modCount++,此参数是指当前列表结构被修改的次数
        modCount++;
        // 判断当前数据量是否大于数组的长度
        if (minCapacity - elementData.length > 0)
            //如果大于则进行扩容操作
            grow(minCapacity);
    }
    //扩容方法
    private void grow(int minCapacity) {
    
        // 记录扩容前数组的长度
   
  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值