java基础之ArrayList扩容机制

/**
* 要分配的最大数组大小
*/
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);
}

int newCapacity = oldCapacity + (oldCapacity >> 1),所以ArrayList每次扩容之后容量都会变成之前的1.5倍(JDK1.6版本以后),JDK。6版本时,扩容之后的容量为1.5倍+1

“>>”(位移运算符):>>1右移一位相当于除以2,右移n位相当于除以2的n次方。这里oldCapacity明显右移了1位,所以相当于oldCapacity/2,对于大数据的2进制运算,位移运算符比那些普通运算符要快很多,因为程序仅仅移动一下而已,不用去计算,这样提高了效率,节省了资源

通过例子来探寻一下grow()方法:
  • 当add第一个元素时,oldCapacity为0,经过比较后第一个if判断成立,但第二个if判断不会成立,即newCapacity不比MAX_ARRAY_SIZE大,则不会进入hugeCapacity方法,数组容量为10,add方法中return true,size增为1.

  • 当add第11个元素进入grow方法时,newCapacity为15,比minCapacity(11)大,第一个判断不成立。新容量没有大于数组最大size,不会进入hugeCapacity方法,数组容量扩为15,add方法中return true,size增为11

  • 以此类推

补充:
  • java中的length属性是针对数组说的,比如说声明了一个数组,想知道这个数组的长度则用到length这个属性

  • java中的length()方法是针对字符串来说的,如果想知道这个字符串的长度,则用到length()方法

  • java中的size()方法是针对泛型集合说的,如果想看这个泛型有多少元素,用这个方法

hugeCapacity()方法

从上面grow()方法源码我们知道:如果新容量大于MAX_ARRAY_SIZE,进入(执行)hugeCapacity()方法来比较minCapaclity和MAX_ARRAY_SIZE,如果minCapacity大于最大容量,则新容量为Integer.MAX_VALUE,否则新容量大小则为MAX_ARRAY_SIZE,即Integer.Max_VALUE - 8;

    private static int hugeCapacity(int minCapacity) {
       if (minCapacity < 0) // overflow
           throw new OutOfMemoryError();
       //对minCapacity和MAX_ARRAY_SIZE进行比较
       //若minCapacity大,将Integer.MAX_VALUE作为新数组的大小
       //若MAX_ARRAY_SIZE大,将MAX_ARRAY_SIZE作为新数组的大小
       //MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
       return (minCapacity > MAX_ARRAY_SIZE) ?
           Integer.MAX_VALUE :
           MAX_ARRAY_SIZE;
  }
ensureCapacity方法
    /**
   如有必要,增加此 ArrayList 实例的容量,以确保它至少可以容纳由minimum capacity参数指定的元素数。
    *
    * @param   minCapacity   所需的最小容量
    */
   public void ensureCapacity(int minCapacity) {
       int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
           // any size if not default element table
           ? 0
           // larger than default for default empty table. It's already
           // supposed to be at default size.
          : DEFAULT_CAPACITY;

       if (minCapacity > minExpand) {
           ensureExplicitCapacity(minCapacity);
      }
  }

最好在add大量元素之前使用ensureCapacity方法,以减少重新分配的次数

 

 

posted @   时光不染-^^-  阅读(371)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
点击右上角即可分享
微信分享提示