WELCOME TO XIPIAN'S BLOG|

xipian

园龄:2年11个月粉丝:1关注:0

ArrayList和Vector扩容机制

ArrayList和Vector扩容机制源码(JDK8)探索

ArrayList和Vector都是实现了List接口的集合类,元素有序可重复,支持索引;
其中ArrayList是线程不安全的,Vector是线程安全的。两者都通过Object类型的数组elementData存放元素;其扩容机制如下:
先说结论:

  • ArrayList
    • 无参构造时,初始elementData为空,第一次添加元素时扩容为10,以后按1.5倍扩容
    • 有参构造时,初始为传入参数大小,以后按1.5倍扩容
  • Vector
    • 无参构造时,初始为10,按2倍扩容
    • 有参构造时,初始为传入参数大小,按2倍扩容

下面从JDK8的源码分析一下:

ArrayList扩容机制

  • 首先是ArrayList无参构造时,debug用的代码如下:

    ArrayList arrayList = new ArrayList();
    for (int i = 0; i < 20; i++) {
    arrayList.add(i);
    }
    1. 无参new一个ArrayList对象时,会调用无参构造器:

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

      而在ArrayList里DEFAULTCAPACITY_EMPTY_ELEMENTDATA的定义为

      private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

      所以初始化后,elementData是空的:

      图1

    2. 接下来开始往里面添加元素:

      public boolean add(E e) {
      ensureCapacityInternal(size + 1); // Increments modCount!!
      elementData[size++] = e;
      return true;
      }
      private void ensureCapacityInternal(int minCapacity) {
      ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
      }
      private static int calculateCapacity(Object[] elementData, int minCapacity) {
      if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
      return Math.max(DEFAULT_CAPACITY, minCapacity);
      }
      return minCapacity;
      }
      //这里判断我们这个对象的数组是否是初始化的那个数组,如果是,则返回DEFAULT_CAPACITY和minCapacity中的最大值,因为这是第一次添加元素,所以就是初始化的那个数组,所以返回两者的最大值,这里DEFAULT_CAPACITY=10(定义的final常量),minCapacity=1(传入的数值),所以返回10.
      private static final int DEFAULT_CAPACITY = 10;
      private void ensureExplicitCapacity(int minCapacity) {//传入10
      modCount++;
      // overflow-conscious code
      if (minCapacity - elementData.length > 0)
      grow(minCapacity);
      }
      private void grow(int minCapacity) {//传入10
      // overflow-conscious code
      int oldCapacity = elementData.length;//=0
      int newCapacity = oldCapacity + (oldCapacity >> 1);//位运算,相当于/2,所以是1.5倍的oldCapacity,这里仍旧等于0
      if (newCapacity - minCapacity < 0)
      newCapacity = minCapacity;//=10
      if (newCapacity - MAX_ARRAY_SIZE > 0)//MAX_ARRAY_SIZE是一个很大的数,先不用管
      newCapacity = hugeCapacity(minCapacity);
      // minCapacity is usually close to size, so this is a win:
      elementData = Arrays.copyOf(elementData, newCapacity);//扩容为10
      }

      然后就是添加数据,可以看到,elementData已经扩容为10:

      image-20230328212742708

    3. 当添加到第十一个元素时,流程基本一致,grow函数那里流程有点不同:

      private void grow(int minCapacity) {//传入11
      // overflow-conscious code
      int oldCapacity = elementData.length;//=10
      int newCapacity = oldCapacity + (oldCapacity >> 1);//=15
      if (newCapacity - minCapacity < 0)
      newCapacity = minCapacity;
      if (newCapacity - MAX_ARRAY_SIZE > 0)
      newCapacity = hugeCapacity(minCapacity);
      // minCapacity is usually close to size, so this is a win:
      elementData = Arrays.copyOf(elementData, newCapacity);//扩容为15
      }

      可以看到,elementData已经扩容为15:

      image-20230328222603727

  • ArrayList有参构造时,debug用的代码如下:

    ArrayList arrayList = new ArrayList(8);
    for (int i = 0; i < 20; i++) {
    arrayList.add(i);
    }
    1. 调用有参构造器:

      public ArrayList(int initialCapacity) {
      if (initialCapacity > 0) {
      this.elementData = new Object[initialCapacity];//new一个Object类型的数组,大小为参数大小
      } else if (initialCapacity == 0) {
      this.elementData = EMPTY_ELEMENTDATA;
      } else {
      throw new IllegalArgumentException("Illegal Capacity: "+
      initialCapacity);
      }
      }

      初始化的容量为8:

      image-20230328223705603

    2. 然后后续添加过程的按1.5倍扩容,过程和上面的一致

Vector扩容机制

  • 首先是Vector无参构造时,debug用的代码如下:

    Vector vector = new Vector();
    for (int i = 0; i < 20; i++) {
    vector.add(i);
    }
    1. 调用无参构造器:(可以看到,无参构造器直接调用了有参构造器,并传入了一个10

      public Vector() {
      this(10);
      }
    2. 调用有参构造器:(这里又调用了两个参数的有参构造器,另一个参数是0

      public Vector(int initialCapacity) {
      this(initialCapacity, 0);
      }
      public Vector(int initialCapacity, int capacityIncrement) {
      super();
      if (initialCapacity < 0)
      throw new IllegalArgumentException("Illegal Capacity: "+
      initialCapacity);
      this.elementData = new Object[initialCapacity];//new一个第一个参数大小的Object类型的数组,这里是10
      this.capacityIncrement = capacityIncrement;//=0
      }

      可以看到,elementData容量已经初始化为10:

      image-20230328230234295

    3. 接下来往里面添加第一个元素:

      public synchronized boolean add(E e) {
      modCount++;
      ensureCapacityHelper(elementCount + 1);
      elementData[elementCount++] = e;
      return true;
      }
      private void ensureCapacityHelper(int minCapacity) {//传入1,代表需要一个空间
      // overflow-conscious code
      if (minCapacity - elementData.length > 0)
      grow(minCapacity);//如果需要的空间大于数组的大小,则需要扩容,这里暂时不需要
      }

      所以不需要扩容,直接就往里面添加第一个元素了:

      image-20230328232447342

    4. 当添加到第11个元素时,需要扩容了,进入grow()函数:

      private void grow(int minCapacity) {//传入11
      // overflow-conscious code
      int oldCapacity = elementData.length;//=10
      int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
      capacityIncrement : oldCapacity);
      //capacityIncrement在构造器那里已经初始化为0,所以这个返回的时oldCapacity+oldCapacity,即2倍的elementData.length
      if (newCapacity - minCapacity < 0)
      newCapacity = minCapacity;
      if (newCapacity - MAX_ARRAY_SIZE > 0)
      newCapacity = hugeCapacity(minCapacity);
      elementData = Arrays.copyOf(elementData, newCapacity);//数组扩容为2倍大小
      }

      image-20230328233910435

  • 有参构造时,和上述顺序一致,因为无参构造时也是调用了一个参数的构造器。


  • 学习过程记录,如有错误,欢迎评论区或私聊指正,谢谢啦!!

本文作者:xipian

本文链接:https://www.cnblogs.com/xipian/p/17281273.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   xipian  阅读(77)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起