【java】阅读JDK19集合源码 - 动态数组:ArrayList和Vector的构造器扩容机制源码浅析

ArrayList

ArrayList是list接口的重要实现类。其作为动态数组存在,可以不断扩充数组大小。注意ArrayList是线程不安全的。反之,vector是线程安全的,两者的主要用途是一致的。

扩容机制
  1. ArrayList支持初始化时提供一个list大小initialCapacity,如果不提供,则默认值为0。
  2. 加入元素的时候扩容elementData为10,在这之后,每当我们往其中加入数据超出限制,都会让list扩容当前容量的1.5倍。
  3. 如果提供初始initialCapacity,则只有加入元素超限时才会扩容当前容量的1.5倍。
源码
动态数组本质

ArrayList使用的一个数组Object[] elementData来实现数据的存储。对于不同的ArrayList初始化方法,elementData会被初始化为不同的数组。

//transient关键字表示该属性不会被序列化
transient Object[] elementData;

//无参构造器中使用的数组
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

//空数组,有参构造器中使用
private static final Object[] EMPTY_ELEMENTDATA = {};

构造器

首先,无参构造器允许我们创建一个空数组

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

指定构造器

    public ArrayList(int initialCapacity) {
        //直接为指定的大小分配一个初始容量
        if (initialCapacity > 0) {
            this.elementData = new Object[initialCapacity];
        //如果给出的大小为0,认定这是一个空数组EMPTY_ELEMENTDATA
        } else if (initialCapacity == 0) {
            this.elementData = EMPTY_ELEMENTDATA;
        } else {
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        }
    }
add方法

对于add方法,源码如下

    //对外的接口
    public boolean add(E e) {
        //modCount负责记录集合被修改的次数
        modCount++;
        //调用重载的add方法
        add(e, elementData, size);
        return true;
    }

    //实际执行的add重载方法
    private void add(E e, Object[] elementData, int s) {
        //首先查看size是否已经超出了限制
        if (s == elementData.length)
            //如果超出,执行grow使数组扩容
            elementData = grow();
        //空间充足时,数组[s] = e;
        elementData[s] = e;
        size = s + 1;
    }
扩容

主要的扩容机制通过grow函数实现。

    private Object[] grow(int minCapacity) {
        int oldCapacity = elementData.length;
        //如果elementData不为空
        //或者elementData不是DEFAULTCAPACITY_EMPTY_ELEMENTDATA
        //即使用了有参构造器构造的Arraylist
        if (oldCapacity > 0 || elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            int newCapacity = ArraysSupport.newLength(oldCapacity,
                    //最小的长度扩增,为1,至少满足当前元素的插入需求
                    minCapacity - oldCapacity, /* minimum growth */
                    //理想扩容为原容量的1.5倍,这是首选的扩容大小
                    oldCapacity >> 1           /* preferred growth */);
            //获取一个原数组的copy,其原数组的长度修改为新的容量
            return elementData = Arrays.copyOf(elementData, newCapacity);
        } else {
            //如果原数组初始化时赋值为0
            //为其赋值数组大小为DEFAULT_CAPACITY和minCapacity
            //注意,主要原因是因为可能直接添加一个其他集合到ArrayList
            //DEFAULT_CAPACITY == 10
            return elementData = new Object[Math.max(DEFAULT_CAPACITY, minCapacity)];
        }
    }

Vector

扩容机制

vector的扩容机制和ArrayList是类似的

  1. 如果是无参构造器创建的,设置默认容量为10
  2. 每次扩容为原容量的两倍。
源码
动态数组本质

Vector没有ArrayList的多种不同的空数组,处理比较简单粗暴,其实现动态数组的字段也是一个Object数组elementData

protected Object[] elementData;
构造器

有参构造器(携带初始容量)

    public Vector(int initialCapacity) {
        this(initialCapacity, 0);
    }

    //这个方法提供了指定capacityIncrement的途径
    //capacityIncrement可以指定每次自动扩增的大小,如指定其为1,每次容量仅增加1
    //默认的capacityIncrement为0,在这种情况下,每次增加的量为原本长度
    public Vector(int initialCapacity, int capacityIncrement) {
        super();
        if (initialCapacity < 0)
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        this.elementData = new Object[initialCapacity];
        this.capacityIncrement = capacityIncrement;
    }

无参构造器直接调用了有参构造器,并设置初始值为10,这是和ArrayList的一个主要区别

    public Vector() {
        this(10);
    }
add方法

Vector的add实现和ArrayList几乎一致,当然,入口方法通过synchronized进行了锁保护。


    public synchronized boolean add(E e) {
        //集合修改次数++
        modCount++;
        //调用重载的add方法
        add(e, elementData, elementCount);
        return true;
    }

    private void add(E e, Object[] elementData, int s) {
        //如果达到上限,进行扩容
        if (s == elementData.length)
            elementData = grow();
        elementData[s] = e;
        elementCount = s + 1;
    }


扩容

Vector的扩容机制没有分具体的初始化情况进行区分。具体内容与ArrayList仍然类似。

    private Object[] grow(int minCapacity) {
        int oldCapacity = elementData.length;
        int newCapacity = ArraysSupport.newLength(oldCapacity,
                //最小增长值为新老容量之差,至少必须装下当前插入的值
                minCapacity - oldCapacity, /* minimum growth */
                //如果capacityIncrement>0,就采取用户设置的每次增长量
                //如果等于0,就为默认的每次增加一倍(oldCapacity)
                capacityIncrement > 0 ? capacityIncrement : oldCapacity
                                           /* preferred growth */);
        return elementData = Arrays.copyOf(elementData, newCapacity);
    }

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值