
本文详解 java 中自定义动态数组类的扩容逻辑,重点解决因未同步更新容量字段导致的扩容失效问题,并提供可直接运行的修复代码与最佳实践建议。
在 Java 中,原生数组(int[])是固定长度的,无法直接“改变大小”。因此,实现一个类似 ArrayList 的动态数组类时,核心在于:当容量不足时,创建一个更大的新数组 → 将旧数据复制过去 → 用新数组替换旧引用。但仅完成内存分配和数据拷贝还不够——若未同步更新用于容量判断的字段,扩容将形同虚设。
观察原始代码,问题根源在于 resize() 方法中:
private void resize() {
int[] temp = new int[size * 2]; // ❌ 错误:仍用过时的 size 字段计算新容量
for (int i = 0; i < array.length; i++) {
temp[i] = array[i];
}
array = temp; // ✅ 正确:完成引用切换
// ❌ 缺失:未更新 size 字段!后续 isFull() 仍按旧 size 判断
}由于 size 始终保持初始值(如 5),isFull() 方法实际比较的是 pointer == array.length(即当前物理容量),而 resize() 却用恒定的 size * 2 创建新数组——这看似“扩容”,但下次 isFull() 仍会立即返回 true,因为 pointer 已达旧长度,而 size 未变,导致无限扩容循环或逻辑错乱。
✅ 正确做法是:移除冗余的 size 字段,直接使用 array.length 表示当前容量。Java 数组对象自带 .length 属性,既准确又无需维护。同时,print() 方法也应遍历有效元素个数(pointer),而非整个数组长度,否则会输出大量默认值 0:
立即学习“Java免费学习笔记(深入)”;
public class Array {
private int[] array;
private int pointer; // 当前已存储元素个数(逻辑大小)
private static final int DEFAULT_CAPACITY = 5;
public Array() {
this(DEFAULT_CAPACITY);
}
public Array(int initialCapacity) {
this.array = new int[initialCapacity];
this.pointer = 0;
}
public void add(int element) {
if (pointer == array.length) { // 直接用 array.length 判断是否满
resize();
}
array[pointer++] = element;
}
private void resize() {
int newCapacity = array.length * 2;
int[] temp = new int[newCapacity];
System.arraycopy(array, 0, temp, 0, array.length); // 推荐:比手动循环更高效
array = temp;
}
public void print() {
for (int i = 0; i < pointer; i++) { // ✅ 只打印已添加的元素
System.out.println(array[i]);
}
}
// 可选:提供获取当前元素数量的方法
public int size() {
return pointer;
}
// 可选:提供获取当前容量的方法
public int capacity() {
return array.length;
}
}⚠️ 关键注意事项:
- 避免维护重复状态:size 字段与 array.length 语义重叠,易引发不一致;应以 array.length 为唯一容量真相源。
- 复制效率优先:使用 System.arraycopy() 替代手动 for 循环,JVM 对其有深度优化。
- 边界安全:add() 中先检查再插入,确保 pointer 不越界;print() 使用 pointer 遍历,杜绝无效输出。
- 命名清晰化:将 size 字段重命名为 pointer(或 size 表示逻辑大小),更能体现其“已用位置索引”的本质。
通过以上修正,你的 Array 类即可稳定支持自动扩容,行为与 ArrayList 的核心扩容逻辑高度一致——这也是理解 Java 集合框架底层原理的重要一步。










