集合常见问题

  1. ArrayList

ArrayList的扩容机制

1. List中的成员变量和方法

默认的初始容量大小

 private static final int DEFAULT_CAPACITY  = 10

保存元素的数组

 transient Object[] elementData    

默认的初始化空数组存储

 private static final Object [] DEFAULTCAPACITY_EMPTY_ELEMENTDATA={}

默认空参数构造器

 /**
  * 默认构造函数,使用初始容量10构造一个空列表(无参数构造)
  */
 public ArrayList() {
     this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
 }
 ​

2.ADD方法

 private boolean add(E e){
   //添加元素之前,确认内部数组的容量
   ensureCapacityInternal(size+1);
   //添加元素
   elementData[size++]=e;
   return true;  
 }
 // 根据给定的最小容量和当前数组元素来计算所需容量。
 private static int calculateCapacity(Object[] elementData, int minCapacity) {
     // 如果当前数组元素为空数组(初始情况),返回默认容量和最小容量中的较大值作为所需容量
     if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
         return Math.max(DEFAULT_CAPACITY, minCapacity);
     }
     // 否则直接返回最小容量
     return minCapacity;
 }
 ​
 // 确保内部容量达到指定的最小容量。
 private void ensureCapacityInternal(int minCapacity) {//minCapacity 中时间传进来的数据是Size+1
     ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
 }
 ​

在ensureExplicitCapacity方法中进行内部扩容

 //判断是否需要扩容
 private void ensureExplicitCapacity(int minCapacity) {
     modCount++;
     //判断当前数组容量是否足以存储minCapacity个元素
     if (minCapacity - elementData.length > 0)
         //调用grow方法进行扩容
         grow(minCapacity);
 }
 ​

3. 扩容机制分析

我们现在以添加一个元素的过程来分析ArrayList 的扩容机制,首先new ArrayList<>(),这个时间,调用了无参构造器,所以当前elementData 的数值是DefaultCapacity_EMPTY_ELEMEMTDATA ,他是一个空数组。

添加一个数字1,调用add (E e) 方法,再去调用 ensureCapacityInternal(size+1) size+1=1,内部调用ensureExeplicitCapacity方法,在次调用caculateCapacity方法中,因为是第一次插入元素,所以elementData是默认的空数组,也就是DEFAULTCAPACITY_EMPTY_ELEMENTDATA,所以返回的长度是两个DEFAULT_CAPACITY和minCapacity中最大的一个,也就是10(DEFAULT_CAPACITY)。

然后再来看当前的ensreExepliciCapacity()方法,他的参数是minCapacity,由CaculateCapacity方法返回的数值是10,在当前方法中判断其中min 》 size,进行扩容。

再来看看grow 方法,

  • 添加第一个元素,现在的elementData 是 默认的空数组,所以返回的长度是Math.max(Default_Capacity(10),minCapacity(1));然后再Exeplicit 方法中,minCapacity- elementData.length > 0 ,进行扩容。

  • 添加第二个元素,catulateCapacity 方法返回的是 1,因为elementData 已经不是默认的空数组了,再进入ExeplicitCapacity 方法中,min- element > 0 不成立,就不去执行grow 方法。

  • 添加到11 个元素的时间,ExeplicitCapacity,进行扩容方法。扩大为原来的1.5 倍数,

 /**
  * 要分配的最大数组大小
  */
 private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
 ​
 /**
  * ArrayList扩容的核心方法。
  */
 private void grow(int minCapacity) {
     // oldCapacity为旧容量,newCapacity为新容量
     int oldCapacity = elementData.length;
     // 将oldCapacity 右移一位,其效果相当于oldCapacity /2,
     // 我们知道位运算的速度远远快于整除运算,整句运算式的结果就是将新容量更新为旧容量的1.5倍,
     int newCapacity = oldCapacity + (oldCapacity >> 1);
 ​
     // 然后检查新容量是否大于最小需要容量,若还是小于最小需要容量,那么就把最小需要容量当作数组的新容量,
     if (newCapacity - minCapacity < 0)
         newCapacity = minCapacity;
 ​
     // 如果新容量大于 MAX_ARRAY_SIZE,进入(执行) `hugeCapacity()` 方法来比较 minCapacity 和 MAX_ARRAY_SIZE,
     // 如果minCapacity大于最大容量,则新容量则为`Integer.MAX_VALUE`,否则,新容量大小则为 MAX_ARRAY_SIZE 即为 `Integer.MAX_VALUE - 8`。
     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
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值