ArrayList和Vector扩容机制

发布时间 2023-04-02 20:41:41作者: xipian

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

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


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