首页 > 其他分享 >ArrayList和Vector扩容机制

ArrayList和Vector扩容机制

时间:2023-04-02 20:44:10浏览次数:25  
标签:扩容 10 Vector int ArrayList elementData newCapacity minCapacity

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

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


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

标签:扩容,10,Vector,int,ArrayList,elementData,newCapacity,minCapacity
From: https://www.cnblogs.com/xipian/p/17281273.html

相关文章

  • Perceptron, Support Vector Machine and Dual Optimization Problem (3)
    SupportVectorMachinesPerceptronandLinearSeparability假设存在一个lineardecisionboundary,它可以完美地对trainingdataset进行分割。那么,经由上述PerceptronAlgorithm计算,它将返回哪一条linearseparator?当linearseparator(即一个给定的超平面)的margi......
  • STL 容器 002 (vector 详解)
    为什么各方面表现都比较中等,适用范围广尾插很快,查找也比较快是什么动态数组特点:动态数组,三个指针控制两倍增长扩充的方法:不能原地扩充,因为后面可能会有其他的东西,必须在其他地方开辟一块更大的内存提供[]所有的有连续空间的容器都有[]itera......
  • unity [数学] 四元数和Vector3相乘的意义
    参考:https://answers.unity.com/questions/186252/multiply-quaternion-by-vector.html 总结:Quaternion*Vector3表示在世界坐标系下,Vector3的任意旋转; Inthequaternionworld,multiplicationisthewaytoapplytherotationtosomething  【在Quaternion下,相......
  • Google Docs悄然扩容至5GB 为Google Drive铺路?
    这些年来有种种迹象表明GoogleDrive即将到来,但是人们发现这货一直在跳票一直在忽悠用户,不过这一次,谷歌的GoogleDrive云存储服务恐怕是真的要来了。是怎么一回事儿呢?一起来......
  • 阿里云ECS磁盘扩容
    环境:OS:Centos7 1.控制台添加云盘 2.创建pvpvcreate/dev/sdc 3.扩充VG[root@19c~]#vgsVG#PV#LV#SNAttrVSizeVFreecentos220......
  • ArrayList源码分析(需要找时间在刷一遍)
          ......
  • 吃巧克力,容器vector、map,容器适配器 priority_queue,算法sort排序
     #include<algorithm>#include<queue>#include<map>#include<vector>#include<iostream>usingnamespacestd;structchocolate{longlonga;//价......
  • minio serverpool 进行集群扩容测试试用
    minio以前是推荐联邦解决集群的问题,但是现在已经废弃了,推荐通过serverpool模式进行集群的扩容处理,而且提供了比较全的命令还是比较方便的以下是一个简单的测试:包含了......
  • LVM扩容
    Linux下的LVM扩容加入新的磁盘fdisk-l使用cfdisk创建分区cfdisk/dev/sdb选择lvm格式扩展物理卷扩容这个vgextend/dev/mapper/ubuntu--vg-ubuntu--l......
  • StatefulSet 扩容和缩容
    概念和Deployment类似,可以通过更新replicas字段扩容/缩容StatefulSet,也可以使用kubectlscale、kubectleditkuectlpatch来扩容/缩容一个StatefulSet扩容kube......