ArrayList部分源码分析(jdk8)

ArrayList底层是用数组实现的存储。与它类似的是LinkedList,和LinkedList相比,它的查找和访问元素的速度较快,但新增,删除的速度较慢。
ArrayList是线程不安全的,一般常用于查询操作,如果涉及频繁的增删,可以使用LinkedList,如果你需要线程安全可以使用Vector

一、ArrayList属性

	//序列号
    private static final long serialVersionUID = 8683452581122892189L;
 
    //默认初始容量
    private static final int DEFAULT_CAPACITY = 10;
 
    //一个空数组,当用户指定ArrayList容量为0时,返回该数组
    private static final Object[] EMPTY_ELEMENTDATA = {};
    /**
     * 一个空数组实例
     * -- 当用户没有指定 ArrayList 的容量时(即调用无参构造函数),返回的是该数组==>刚创建一个 
     *   ArrayList时,其内数据量为 0。
     * -- 当用户第一次添加元素时,该数组将会扩容,变成默认容量为 10(DEFAULT_CAPACITY) 的一
     * 	  个数组===>通过ensureCapacityInternal() 实现
     *    它与 EMPTY_ELEMENTDATA 的区别就是:该数组是默认返回的,而后者是在用户指定容量为 0 时返回
     */
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
 
    //当前数据对象存放地方,当前对象不参与序列化
    //这个关键字最主要的作用就是当序列化时,被transient修饰的内容将不会被序列化
    transient Object[] elementData; // non-private to simplify nested class access
 
    //ArrayList实际存储的数据数量
    private int size;
 
    //继承于AbstractList
    //集合数组修改次数的标识
    protected transient int modCount = 0;

二、 ArrayList构造函数

	/**
	创建指定容量的ArrayList
	*/
    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);
        }
    }

   /**
     *   无参构造函数:
     * - 创建一个空的 ArrayList,此时其内数组缓冲区 elementData = {}, 长度为 0
     * - 当元素第一次被加入时(第一次add元素时),扩容至默认容量 10
     */
    public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }

    /**
     *  创建一个包含collection的ArrayList
     */
    public ArrayList(Collection<? extends E> c) {
        elementData = c.toArray();
        if ((size = elementData.length) != 0) {
            // c.toArray might (incorrectly) not return Object[] (see 6260652)
            if (elementData.getClass() != Object[].class)
                elementData = Arrays.copyOf(elementData, size, Object[].class);
        } else {
            // replace with empty array.
            this.elementData = EMPTY_ELEMENTDATA;
        }
    }

三、常用方法

1、add(E e)将指定的元素追加到此列表的末尾。
 	/**
     *增加指定的元素到ArrayList的最后位置
     * @param e 要添加的元素
     */
    public boolean add(E e) {
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        elementData[size++] = e;
        return true;
    }
	
    private void ensureCapacityInternal(int minCapacity) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
        	//取最大值
            minCapacity= Math.max(DEFAULT_CAPACITY, minCapacity);
        }
        ensureExplicitCapacity(minCapacity);
    }
    /**
     * 判断数组是否主要扩容
     */
    private void ensureExplicitCapacity(int minCapacity) {
        // 将“修改统计数”+1,该变量主要是用来实现fail-fast机制的
        modCount++;
        /**
        *   到此步元素还未添加到数组里
        *   判断数组真实元素个数加1后的长度与当前数组长度大小关系,
        *	如果小于0,数组还有容量可以add值,返回,如果大于0,说明无容量,则扩容
        *	使用无参构造,第一次add,此时elementData数组为空,minCapacity - elementData.length>0,
        *	此时grow()方法会分配初始容量,有指定容量构造,elementData不为空,第一次add无需扩容
        */
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }
 
    /**
     * 数组缓冲区最大存储容量
     */
    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
 
    /**
     * 数组扩容,以确保 ArrayList 至少能存储 minCapacity 个元素
     * 扩容计算:newCapacity = oldCapacity + (oldCapacity >> 1);  扩充当前容量的1.5倍
     */
    private void grow(int minCapacity) {
        int oldCapacity = elementData.length;
        // 运算符 >> 是带符号右移. 扩大1.5倍
        // 如 oldCapacity = 10,则 newCapacity = 10 + (10 >> 1) = 10 + 5 = 15
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        if (newCapacity - minCapacity < 0)  // 若 newCapacity 依旧小于 minCapacity
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)   
        // 若 newCapacity 大于最大存储容量,则进行大容量分配
           newCapacity = hugeCapacity(minCapacity);
           //把原数组元素复制到扩容后的数组
        elementData = Arrays.copyOf(elementData, newCapacity);
    }
    /**
     * 私有方法:大容量分配,最大分配 Integer.MAX_VALUE
     * @param minCapacity
     */
    private static int hugeCapacity(int minCapacity) {
        if (minCapacity < 0) // overflow
            throw new OutOfMemoryError();
        return (minCapacity > MAX_ARRAY_SIZE) ?
                Integer.MAX_VALUE :
                MAX_ARRAY_SIZE;
    }

使用无参构造,底层数组elementData为空,在第一次add的时候才会分配DEFAULT_CAPACITY = 10的初始容量。有指定容量构造,则使用指定容量。在真正添加元素之前,会先判断数组是否需要扩容。

2.add(int index, E element)在此列表中的指定位置插入指定的元素。
 public void add(int index, E element) {
        //判断索引是否越界
        rangeCheckForAdd(index);
        //确保已使用数组长度size+1能够存下数据
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        //elementData:要复制的数组,index从哪里开始复制
        //elementData:目标数组,index复制到的数组第几个开始,最后一个是复制长度
        
        System.arraycopy(elementData, index, elementData, index + 1,
                         size - index);
        elementData[index] = element;
        size++;
}

System.arraycopy(elementData, index, elementData, index + 1, size - index);是怎么操作的如图:
在index1上插入d,由index1开始复制,放到index+1的位置上,把index1位置空出来,然后进行插入操作。当数据量很大时,速度会有影响。
在这里插入图片描述

3.get(int index)返回此列表中指定位置的元素。

这个方法很简单,就是通过索引查找元素

  public E get(int index) {
  	   //判断索引是否越界
        rangeCheck(index);
        return elementData(index);
    }
4.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);
        elementData[--size] = null; // clear to let GC do its work
        return oldValue;
    }

System.arraycopy(elementData, index+1, elementData, index,numMoved);如图:
删除index1上元素,就是把index+1开始复制,复制到index上,相当于覆盖原来index1上的元素。
在这里插入图片描述
本篇文章就说那么多了,其他代码大家可以自行查看,应该都能看明白。
ArrayList特点:查询效率高,增删效率低,线程不安全。使用频率很高。

参考:https://www.cnblogs.com/gxl1995/p/7534171344218b3784f1beb90d621337.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值