ArrayList扩容原理

📦 1. 初始容量与触发条件

  •  

    ​初始容量​​:当使用无参构造函数创建 ArrayList时,其默认初始容量为 ​​10​​(在 JDK 7 及之后的版本中,初始数组通常是一个空引用,直到第一次添加元素时才会分配一个长度为10的数组)。你也可以通过带参数的构造函数(如 new ArrayList<>(20))来指定一个初始容量,这有助于在预先知道元素大致数量时避免初期的频繁扩容。

  •  

    ​触发扩容的条件​​:每当调用 add()或 addAll()方法添加新元素时,ArrayList会检查当前元素的数量(size)加1是否超过了底层数组的长度(elementData.length)。如果 size + 1 > elementData.length,则会触发扩容机制。

⚙️ 2. 扩容的核心步骤

扩容过程主要通过 grow()方法实现,其核心步骤和策略如下:

  1.  

    ​计算新容量​​:

    • 新容量的计算通常遵循 ​​1.5倍​​ 的原则(即 newCapacity = oldCapacity + (oldCapacity >> 1)),这里的位运算 oldCapacity >> 1等价于除以2。

    • 例如,若当前容量为10,则扩容后新容量为 10 + (10 >> 1) = 15

    • 这是一种在​​内存空间利用​​和​​扩容操作频率​​之间取得的平衡。倍数过大(如2倍)可能导致空间浪费,倍数过小(如1.2倍)则可能导致扩容操作过于频繁。

  2.  

    ​确保最小容量​​:

    • 如果按1.5倍计算出的新容量仍然小于实际需要的最小容量(minCapacity,通常是当前元素数量 size加上本次新增的元素数量),则会​​直接采用 minCapacity作为新容量​​。这一点在使用 addAll()一次性添加多个元素时尤为重要。

  3.  

    ​处理大容量情况​​:

    • ArrayList内部定义了一个最大数组容量限制 MAX_ARRAY_SIZE(通常为 Integer.MAX_VALUE - 8)。

    • 如果计算出的新容量甚至超过了 MAX_ARRAY_SIZE,则会根据 minCapacity的值进一步判断:若 minCapacity大于 MAX_ARRAY_SIZE,则新容量设置为 Integer.MAX_VALUE;否则设置为 MAX_ARRAY_SIZE。如果所需容量极大,可能会抛出 OutOfMemoryError

  4.  

    ​创建新数组并复制数据​​:

    • 确定新容量后,会使用 Arrays.copyOf()方法创建一个​​新的、容量更大的数组​​,并将原有数组中的所有元素​​复制​​到新数组中。

    • 最后,将 ArrayList内部的数组引用 elementData指向这个新数组。

    • 这个复制操作的时间复杂度是 ​​O(n)​​,其中 n 是原数组中的元素数量,这是扩容操作的主要性能开销来源。

⚡️ 3. 扩容的性能影响与优化

  •  

    ​性能影响​​:

    •  

      ​时间开销​​:每次扩容都涉及旧数组数据的复制,这是一个相对耗时的操作。频繁扩容会影响程序性能。

    •  

      ​空间开销​​:扩容后,新数组的容量是旧的1.5倍,可能会存在一些未使用的空间,造成一定的内存浪费。

  •  

    ​优化建议​​:

    •  

      ​预估容量并指定初始容量​​:如果你能大致预估 ArrayList最终会存储的元素数量,最好在创建时通过构造函数指定一个足够的初始容量(例如 new ArrayList<>(1000))。这是​​避免多次不必要的扩容、提升性能最有效的方法​​。

    •  

      ​使用 ensureCapacity()方法手动提前扩容​​:如果你已经创建了一个 ArrayList并且后续需要大量添加元素(例如通过一个循环),可以提前调用 ensureCapacity(int minCapacity)方法,一次性将容量至少扩展到指定的 minCapacity。这可以避免在添加元素过程中多次触发自动扩容。

    •  

      ​在元素添加完成后使用 trimToSize()​:如果你非常在意内存的使用,并且确定后续不会再添加大量新元素,可以调用 trimToSize()方法。这个方法会将底层数组的容量裁剪至当前实际元素的个数,释放多余的空间。但请注意,此操作本身也可能涉及数组复制。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值