
System.arraycopy() 本身不能实现“就地扩容”,它无法改变原有数组的长度或内存地址,也不能让数组在原内存位置“变长”。Java 中数组一旦创建,其长度和内存地址就固定了,这是 JVM 内存模型决定的。所谓“就地扩容”在 Java 中不存在。
为什么 System.arraycopy() 不是就地操作
System.arraycopy() 只是一个高效的数据拷贝工具:它把源数组某段内容复制到目标数组的指定位置。它不分配新数组,也不释放旧数组,更不会修改任何数组对象的 length 字段或内存基址。
源数组和目标数组必须是两个独立的对象(可以相同,但仍是同一块内存的读写) 如果目标数组容量不足,会抛出 ArrayStoreException 或 IndexOutOfBoundsException 即使源目标是同一个数组,也仅用于“内部平移”(如删除元素后左移),而非扩容
真正的扩容必须创建新数组
要“扩容”,只能新建一个更长的数组,再用 System.arraycopy() 把旧数据搬过去——这本质是复制+替换,不是就地扩展:
int[] oldArr = {1, 2, 3};int[] newArr = new int[oldArr.length + 2]; // 新数组,内存地址必然不同System.arraycopy(oldArr, 0, newArr, 0, oldArr.length); // 复制数据oldArr = newArr; // 引用指向新数组(原数组等待 GC)
此时 oldArr 变量指向的是全新分配的一块连续内存,旧数组仍存在(直到被回收),两者物理地址无关。
连续性是新数组自身的属性,不是“延续”旧数组
Java 中每个数组对象在堆上都占用一段连续内存,这是 JVM 自动保证的。但:
新数组的连续内存块与旧数组毫无地址关联 两次 new int[n] 的结果几乎不可能相邻,JVM 堆分配是动态、带碎片管理的 所谓“连续性”只针对单个数组内部有效,跨数组无意义
如果真需要类似“动态连续存储”,考虑替代方案
对频繁扩容且关注局部性/性能的场景,可考虑:
使用 ArrayList:内部已封装扩容逻辑(grow()),自动调用 arraycopy,开发者只需 add() 预估容量初始化:new ArrayList(estimatedSize),减少多次扩容 对象池或缓冲区复用(如 ByteBuffer.allocateDirect),适用于高性能 I/O 场景 避免手动管理:Java 不提供指针或 realloc,强行模拟 C 风格扩容既不可行也不安全

评论(0)