Java中 ArrayList 的扩容机制深度解析

在 Java 8 中,ArrayList 是一个广泛使用的集合类,它提供了动态数组的功能。当 ArrayList 需要容纳更多的元素时,它会自动进行扩容。本文将深入探讨 ArrayList 的扩容机制,特别是 grow 方法的实现细节。

ArrayList 扩容概述

ArrayList 通过一个叫做 elementData 的内部数组来存储元素。当添加元素导致数组满时,ArrayList 会执行扩容操作。扩容过程包括以下几个步骤:

  1. 计算新容量。
  2. 检查是否需要满足最小容量要求。
  3. 确保不超过 JVM 允许的最大数组大小。
  4. 复制旧数组到新数组。

grow 方法源码解析

grow 方法是扩容操作的核心。以下是 grow 方法的源码,以及对关键点的注释说明:

private void grow(int minCapacity) {
    // overflow-conscious code
    int oldCapacity = elementData.length;
    // 计算新的容量为当前容量的1.5倍
    int newCapacity = oldCapacity + (oldCapacity >> 1);
    // 如果新容量仍然小于最小需要容量,则将新容量设置为最小需要容量
    if (newCapacity - minCapacity < 0)
        newCapacity = minCapacity;
    // 如果新容量超过了ArrayList允许的最大容量,则调用hugeCapacity方法确定新容量
    if (newCapacity - MAX_ARRAY_SIZE > 0)
        newCapacity = hugeCapacity(minCapacity);
    // 复制原数组内容到新数组
    elementData = Arrays.copyOf(elementData, newCapacity);
}

private static int hugeCapacity(int minCapacity) {
    if (minCapacity < 0) // 如果minCapacity为负数,说明发生溢出,抛出异常
        throw new OutOfMemoryError();
    // 如果minCapacity大于数组最大容量,则返回Integer.MAX_VALUE,否则返回MAX_ARRAY_SIZE
    return (minCapacity > MAX_ARRAY_SIZE) ?
        Integer.MAX_VALUE :
        MAX_ARRAY_SIZE;
}

private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

关键点解释:

  • 容量计算:通过 oldCapacity + (oldCapacity >> 1) 计算新容量,这是当前容量的1.5倍,意味着每次扩容后容量会增加到原来的150%。

  • 最小容量要求:如果计算出的新容量小于所需的最小容量 minCapacity,则将新容量设置为 minCapacity

  • 最大容量限制:如果新容量超过了 MAX_ARRAY_SIZEInteger.MAX_VALUE - 8),则需要调用 hugeCapacity 方法来限制新容量不超过 JVM 允许的最大值。

  • 数组复制:使用 Arrays.copyOf 方法将旧数组的内容复制到具有新容量的数组中。

异常处理:

  • 溢出处理:如果 minCapacity 计算结果为负数,表示发生了整数溢出,此时抛出 OutOfMemoryError

ArrayList 的扩容机制设计得非常高效和安全。它通过1.5倍的扩容策略减少了扩容的频率,同时通过检查最大容量限制确保了程序的稳定性。

你可能感兴趣的:(java,开发语言)