ArrayList的扩容方式

目录

1.ArrayList基础知识

2.ArrayList的常用方法

3.主要成员变量

4.三种初始化

  4.1.默认的构造器,将会以默认的大小来初始化内部的数组

4. 2.用一个Collection对象来构造,并将该集合的元素添加到ArrayList

 4.3.用户指定大小来初始化内部数组

5.扩容机制(以无参构造创建)

5.1开始于往集合中添加元素方法,即 add方法(有两种)

5.2 再调用ensureExplictCapacity方法

5.3进入扩容核心grow方法

5.4 再调用hugeCapacity方法


1.ArrayList基础知识

ArrayList是Java集合框架中的一个重要的类,在 java.util 中( 使用需要引入)。


public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable {

它继承于AbstractList,实现了List接口。是一个长度可变的集合,提供了增删改查的功能。

ArrayList类实现了RandomAccess接口,可以对元素进行快速访问。

实现了Serializable接口,说明ArrayList可以被序列化,还有Cloneable接口,可以被复制。


集合中允许null的存在。和Vector不同的是,ArrayList不是线程安全的。

2.ArrayList的常用方法

  • public int size()   返回集合的长度。
  • public E get(index index) 获取索引位置的元素
  • public boolean remove(object) 删除指定的元素,返回是否删除成功
  • public E remove(int index) 删除指定索引位置的元素, 返回被删除的元素
  • public E set(int index, E element)修改指定索引位置元素为传入的元素,返回被修改元素

3.主要成员变量

    //默认的容量大小(常量)
    private static final int DEFAULT_CAPACITY = 10;
    //定义的空数组
    private static final Object[] EMPTY_ELEMENTDATA = {};
    //定义的默认空容量的数组
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
    //定义的不可被序列化的数组,实际存储元素的数组
    transient Object[] elementData;
    //数组中的元素的个数
    private int size;

4.三种初始化

  4.1.默认的构造器,将会以默认的大小来初始化内部的数组

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

4. 2.用一个Collection对象来构造,并将该集合的元素添加到ArrayList

    public ArrayList(Collection<? extends E> c) {
        //将构造方法中的参数转换成数组形式,
        elementData = c.toArray();
        //将数组的长度赋值给size
        if ((size = elementData.length) != 0) {
            // c.toArray might (incorrectly) not return Object[] (see 6260652)
            //检查elementData是不是object[]类型,
            //不是的话将其转换成object[].class类型
            if (elementData.getClass() != Object[].class)
                //数组的创建与拷贝
                elementData = Arrays.copyOf(elementData, size, Object[].class);
        } else {
            // replace with empty array.
            //size为0,则把已创建好的空数组直接给它
            this.elementData = EMPTY_ELEMENTDATA;
        }
    }

 4.3.用户指定大小来初始化内部数组

    public ArrayList(int initialCapacity) {
        if (initialCapacity > 0) {
            //如果传进来的变量>0,则初始化一个指定容量的空数组
            this.elementData = new Object[initialCapacity];
        } else if (initialCapacity == 0) {
            //则不去创建新的数组,直接将已创建的EMPTY_ELEMENTDATA空数组传给Arraylist
            this.elementData = EMPTY_ELEMENTDATA;
        } else {
            //<0,则抛出异常
            throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity);
        }
    }

5.扩容机制(以无参构造创建)

5.1开始于往集合中添加元素方法,即 add方法(有两种)

    public boolean add(E e) {
        ensureCapacityInternal(size + 1); 
        elementData[size++] = e;
        return true;
    }
    public void add(int index, E element) {
        rangeCheckForAdd(index);
        ensureCapacityInternal(size + 1); 
        System.arraycopy(elementData, index, elementData, index + 1,
                         size - index);
        elementData[index] = element;
        size++;
    }

阅读上面代码,可以发现两种add()方法都调用了ensureCapacityInternal(size+1)方法

参数minCapacity:size+1:(把数组长度+1以确保能存下下一个数据)

    private void ensureCapacityInternal(int minCapacity) {
        ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
    }

调用 ensureCapacityInternal(size+1)方法之前会调用到下面的  calculateCapacity()方法

此时的minCapacity为1(size在初始化时为0,size+1=1)

注意:1.minCapacity为变量只是第一次调用 add方法时值为1,

            此后调用需要根据实际的数组长度size+1

2.只有在使用无参构造创建数组时,才会返回DEFAULTCAPACITY_EMPTY_ELEMENTDATA数组

在第一次添加值时,会进入到if判断,

最终会返回DEFAULT_CAPACITY固定值(即:10)。

    private static int calculateCapacity(Object[] elementData, int minCapacity) {

        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            //返回默认的容量和传入参数的较大值
            return Math.max(DEFAULT_CAPACITY, minCapacity);
        }
        return minCapacity;
    }

5.2 再调用ensureExplictCapacity方法

    private void ensureExplicitCapacity(int minCapacity) {
        /*
        * modCount表示list已经被结构化修改的次数,主要用在iterator()和listIterator()方法中。
        * 因为add属于结构化的修改,所以这里modCount会加1
        * */
        modCount++;
        if (minCapacity - elementData.length > 0)
            //调用grow进行扩容
            grow(minCapacity);
    }

 如果minCapacity>elementData.length ,会调用到扩容核心grow方法。

注意:

这块的elementData.length返回的是当前数组的容量,而不是数组的实际长度size

如果使用4.3构造创建数组

就需要根据实际情况判断是否调用grow方法。

如果使用无参构造:第一次add时,满足条件,进入grow方法

5.3进入扩容核心grow方法

    private void grow(int minCapacity) {
        //旧容量
        int oldCapacity = elementData.length;
        //将新容量变为旧容量的1.5倍
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        //检查新容量是否大于最小需要容量minCapacity,
        if (newCapacity - minCapacity < 0)
            //若还是小于最小需要容量,就把最小需要容量当做数组的的新容量
            newCapacity = minCapacity;
        //若大于最大容量,
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            //则新容量为Integer.MAX_VALUE,
            //  //若还是小于最小需要容量,就把最小需要容量当做数组的的新容量
            newCapacity = hugeCapacity(minCapacity);
            elementData = Arrays.copyOf(elementData, newCapacity);
    }

int newCapacity = oldCapacity + (oldCapacity >> 1)此行代码即为扩容的核心,oldCapacity为原来的容量,右移一位,即除以2,因此这句的意思就是新的容量:即原来的1.5倍。

然后判断newCapacity如果小于minCapacity时,将minCapacity赋值给newCapacity。

对于使用无参构造时,elementData.length为0,

所以oldCapacity也为0,minCapacity为10,因此最终newCapacity为10。

在进行判断newCapacity是否大于设定的MAX_ARRAY_SIZE,

5.4 再调用hugeCapacity方法

如果minCapacity大于MAX_ARRAY_SIZE,则返回Integer的最大值,

否则返回MAX_ARRAY_SIZE

最后,通过Arrays.copyOf方法把原数组的内容放到更大容量的数组里面。 

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

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值