如何在 Java 中动态调整数组大小

本文详解 java 中手动实现动态数组扩容的核心要点,包括正确更新容量变量、避免越界访问、修复遍历逻辑等关键问题,并提供可直接运行的完整示例代码。

在 Java 中,原生数组(如 int[])是固定长度的,无法直接“改变大小”。但我们可以模拟动态数组行为——当元素数量超出当前容量时,创建一个更大的新数组,将旧数据复制过去,并更新引用。这正是 ArrayList 底层的核心机制。然而,手动实现时极易忽略关键细节,导致扩容失效或逻辑错误。

? 常见错误分析

你提供的 Array 类中存在两个关键缺陷:

  1. size 字段未同步更新
    resize() 方法中创建了新数组 new int[size * 2],但扩容后未更新 this.size。结果:后续调用 isFull() 仍基于原始 size(如 5),而 array.length 已变为 10 —— 两者脱节,isFull() 判断失效,导致下一次添加时可能越界。

  2. print() 方法遍历逻辑错误
    当前使用 for (int i = 0; i

✅ 正确实现方案

以下是修复后的完整代码(关键修改已加注释):

public class Array {
    private int[] array;
    private int pointer; // 当前已存储元素个数(即下一个插入位置)

    public Array() {
        this(5);
    }

    public Array(int initialCapacity) {
        if (initialCapacity < 0) throw new IllegalArgumentException("Capacity must be non-negative");
        this.array = new int[ini

tialCapacity]; this.pointer = 0; } public void add(int element) { if (pointer == array.length) { // 使用 array.length 替代 isFull(),更简洁可靠 resize(); } array[pointer++] = element; } private void resize() { int newSize = array.length * 2; if (newSize == 0) newSize = 1; // 防止初始容量为0时死循环 int[] temp = new int[newSize]; System.arraycopy(array, 0, temp, 0, array.length); // 推荐使用系统级拷贝,高效安全 array = temp; // 注意:无需维护独立的 size 字段!array.length 即当前容量 } public void print() { for (int i = 0; i < pointer; i++) { // 仅打印已添加的元素 System.out.println(array[i]); } } public int size() { return pointer; // 返回逻辑大小(元素个数) } public boolean isEmpty() { return pointer == 0; } }

⚠️ 关键注意事项

  • 移除冗余字段:size 字段完全多余。Java 数组的 .length 属性天然反映当前容量,应直接使用 array.length 进行容量判断和分配。
  • 使用 System.arraycopy:比手动 for 循环拷贝更高效、更安全(尤其对大数组),且能处理 null 和边界校验。
  • pointer 是核心状态变量:它既是已存元素数量,也是下一个插入索引,务必在每次 add() 后自增。
  • 边界防护:resize() 中增加 if (newSize == 0) newSize = 1,避免初始容量为 0 导致无限扩容(虽然本例默认为 5,但增强鲁棒性)。
  • 命名语义化:将 size 字段重命名为 pointer(或更准确的 size 表示逻辑大小),避免与容量(capacity)混淆。当前代码中 pointer 更贴合其作用。

? 测试验证

public static void main(String[] args) {
    Array arr = new Array(2); // 初始容量为2
    arr.add(10);
    arr.add(20);
    arr.add(30); // 触发 resize → 容量变为4
    arr.add(40);
    arr.add(50); // 再次 resize → 容量变为8
    arr.print(); // 输出:10, 20, 30, 40, 50(无多余0)
    System.out.println("Actual size: " + arr.size()); // 输出:5
}

通过以上修正,你的自定义 Array 类即可稳定支持动态扩容,行为与 ArrayList 的核心逻辑一致。掌握这一机制,不仅有助于理解集合框架底层原理,也是面试中高频考察的手写数据结构能力点。