ArrayList扩容方式的理解

首先想想我们什么情况下会扩容,在向数组中添加元素的时候数组容量不够的情况下我们会进行扩容。 

 所以我们先从它的添加元素的方法说起。

add(int index,E element) 

//在指定位置添加一个元素
public void add(int index, E element) {
    rangeCheckForAdd(index);
    //size+1表示要添加这个元素,ArrayList的容量至少为size+1
    ensureCapacityInternal(size + 1); 
    // element放在数组的最后一个位置
    elementData[index] = element;
    //arrayList的元素数量加一
    size++;
}

 我们可以看到有ensureCapacityInternal()方法。确保数组容量在范围内。

ensureCapacityInternal()

// minCapacity表示ArrayList至少需要容量的大小
private void ensureCapacityInternal(int minCapacity) {
  // 确定明确的容量 
  ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}

 calculateCapacity()计算当前ArrayList的容量要扩展到多大。

 calculateCapacity()

private static int calculateCapacity(Object[] elementData, int minCapacity) {
  // 如果底层数组是默认容量的空数组,那就在默认容量和指定容量中取一个最大值,
  // 当然这就意味着 如果底层数组是默认容量空数组,就保证了我要扩至少为10的容量
  if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
      return Math.max(DEFAULT_CAPACITY, minCapacity);
  }
  return minCapacity;
}

ensureExplicitCapacity ()

private void ensureExplicitCapacity(int minCapacity) {
  // 修改次数加一
  modCount++;

  // overflow-conscious code
  if (minCapacity - elementData.length > 0)
      grow(minCapacity);
}

我们看到了grow()方法。这个方法就是所要用到的扩容方法。 

grow() 

 首先获取当前容量oldCapacity,将当前容量的二进制数右移1位后再转为十进制(就是当前容量的1.5倍)就是扩展后的容量(newCapacity)。
如果新容量(newCapacity)比指定的容量(minCapacity)小,那就将指定容量作为新容量,否则新容量就是当前容量的1.5倍。
如果新容量比最大数组容量(MAX_ARRAY_SIZE,即2的31次方-9)还要大,就需要通过hugeCapacity方法进一步确定新容量了,否则新容量依然是当前容量的1.5倍。

hugeCapacity()

如果指定容量小于0,就抛一个内存溢出异常;

如果指定容量大于最大数组容量(MAX_ARRAY_SIZE,就是最大整数减8),就返回最大的整数2的31次方减一,否则就返回最大数组容量。

最大整数为2的31次方-1,最大数组容量为最大整数-8

 为什么要减8 上面的注释是这样解释的:

一些VM在数组中保留一些标题字。尝试分配更大的数组可能会导致OutOfMemoryError:请求的数组大小超过VM限制。

 

回到grow()方法的最后一行。

用了Arrays.copyOf(elementData,newCapacity)方法,将数组和新的容量传进去。 

将elementData数组中的元素复制到新的数组里,复制newCapacity个。

总结:

我们初始化一个ArrayList 集合还没有添加元素时,其实它是个空数组,只有当我们添加第一个元素时,内部会调用扩容方法并返回最小容量10,也就是说ArrayList 初始化容量为10。

当前数组长度小于最小容量的长度时(前期容量是10,当添加第11个元素时就就扩容)ArrayList 扩容的真正计算是在grow()里面,新数组大小是旧数组的1.5倍,如果扩容后的新数组大小还是小于最小容量,那新数组的大小就是最小容量的大小,后面会调用一个Arrays.copyof方法,这个方法是真正实现扩容的步骤。

  • 13
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值