ArrayList源码浅析

ArrayList:
底层实现:数组
如何实现的:

public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }

调用有参构造方法时创建数组的时候,则会创建一个长度为initialCapacity的数组,若initialCapacity为0,则还是相当于调用的无参构造方法

    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);
        }
    }

调用无参构造方法时创建数组的时候:this.elementData数组是{}故初始长度是0
而一般大多数人都会说ArrayList的初始长度是10,这是在第一次添加元素调用add(E e)方法的时候,才会初始化数组的长度为10

  public boolean add(E e) {
  		//调用ensureCapacityInternal方法,传入新的size(因为新加一个元素之前,检查是否在容量之内)
        ensureCapacityInternal(size + 1); 
        //给 elementData赋值之后size+1
        elementData[size++] = e;
        return true;
    }
   private void ensureCapacityInternal(int minCapacity) {
   		//因为是首次调用add方法,故从add方法传过来的minCapacity=size+1,而初始size为0,所以minCapacity=1,调用calculateCapacity得到的返回结果为10
        ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
    }
    private static int calculateCapacity(Object[] elementData, int minCapacity) {
    	//DEFAULTCAPACITY_EMPTY_ELEMENTDATA在ArrayList中定义为{}
    	//DEFAULT_CAPACITY在ArrayList中定义为10
        //因为elementData还未添加值,故下面判断结果为true,则会返回一个最大值DEFAULT_CAPACITY
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            return Math.max(DEFAULT_CAPACITY, minCapacity);
        }
        return minCapacity;
    }
    private void ensureExplicitCapacity(int minCapacity) {
    	//记录修改次数
        modCount++;
        //从ensureCapacityInternal方法中传过来的minCapacity=10,而elementData.length=0
        故满足下面判断条件,则会调用grow(10)
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }
        private void grow(int minCapacity) {
        //oldCapacity=0
        int oldCapacity = elementData.length;
        //ArrayList的扩容代码oldCapacity >> 1=0.5*oldCapacity 
        //所以ArrayList的扩容机制是原来的1.5倍
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        //从上一行代码可知newCapacity=0,进入第一个if语句之后,newCapacity =10
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        //然后复制长度为newCapacity =10的数组给 elementData
        elementData = Arrays.copyOf(elementData, newCapacity);
    }

扩容机制:

     //ArrayList的最大容量
    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
    private void grow(int minCapacity) {
        // 得到ArrayList的旧长度
        int oldCapacity = elementData.length;
        //得到ArrayList的新长度=1.5*旧长度
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        //minCapacity会在ensureExplicitCapacity传过来,如果新长度<minCapacity,则改变新长度为minCapacity
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
         //若生成的新长度比ArrayList的最大容量还要大则调用hugeCapacity方法
        if (newCapacity - MAX_ARRAY_SIZE > 0)
           //得到长度最大值, hugeCapacity方法最大返回Integer.MAX_VALUE
            newCapacity = hugeCapacity(minCapacity);
        // 拷贝数组
        elementData = Arrays.copyOf(elementData, newCapacity);
    }

    private static int hugeCapacity(int minCapacity) {
        if (minCapacity < 0)
            throw new OutOfMemoryError();
        return (minCapacity > MAX_ARRAY_SIZE) ?
            Integer.MAX_VALUE :
            MAX_ARRAY_SIZE;
    }

有参构造方法与无参构造方法的使用情况:
当假设我们有1000条数据加入ArrayList中时,如果使用无参构造,初始化数组的长度0 第一次添加元素的时候开始 长度为10 以后的每次扩容 1.5倍进行扩容10,15,22,33 ,50,75,112 。。。而数组扩容是数组拷贝的过程,非常消耗资源,此时调用有参构造方法,直接初始化长度500时,只需要扩容2次,相比较于无参时,大大节省了资源,从而提高了性能
总结:
ArrayList最大长度只能达到Integer.MAX_VALUE
ArrayList底层是数组的拷贝,所以增删较慢,而因为数组有索引机制,索引查找较快
ArrayList扩容机制是当元素超过其长度时才扩容且扩容为原来长度的1.5倍
ArrayList是线程不安全的
在数据量大的时候,我们创建ArrayList时最好自己初始化长度。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值