System.arraycopy不能直接合并数组,需先创建长度为arr1.length+arr2.length的新数组,再分两次拷贝;仅支持同类型数组,不支持跨类型隐式转换;对象数组仅复制引用,非深拷贝。

System.arraycopy 不能直接合并两个数组,必须先扩容
很多人以为 System.arraycopy 能像 Python 的 + 那样拼接数组,结果发现目标数组长度不够就抛 ArrayStoreException 或静默截断。它只是内存块拷贝工具,不负责分配新空间。
所以合并前必须手动创建一个足够长的新数组,再分两段拷贝。
- 源数组长度之和就是新数组长度:比如
arr1.length + arr2.length - 第一次拷贝从
arr1到新数组起点(0偏移) - 第二次拷贝从
arr2到新数组arr1.length处开始的位置 - 别漏掉
length参数——它指“要拷贝多少个元素”,不是目标索引
原始类型数组合并时,类型必须严格一致
你不能用 System.arraycopy 把 int[] 和 long[] 合并,哪怕只差一个字节。JVM 会直接拒绝,报 ArrayStoreException。连 byte[] 和 short[] 都不行——这不是类型转换,是纯字节搬运。
- 支持同类型拷贝:
String[]→String[]、double[]→double[] - 不支持跨类型隐式转换,哪怕
int可以转long,System.arraycopy也不买账 - 如果真要混类型,得自己遍历转换,或者用
Stream+toArray(但那是另一套开销)
合并对象数组要注意引用拷贝而非深拷贝
System.arraycopy 对对象数组只复制引用地址,不会调用构造函数或克隆对象。如果你后续修改原数组里的某个对象,新数组里同一位置的对象也会变——它们指向同一个堆内存。
- 这是性能优势(快),也是陷阱(共享状态)
- 需要深拷贝时,要么在拷贝后遍历调用
clone()(要求实现Cloneable),要么用序列化/JSON 工具重建 - 常见误判场景:合并两个
List<Map>的数组后,改其中一个Map,另一个也跟着变
替代方案:Arrays.copyOf + copyOfRange 更简洁但有隐含开销
有人图省事用 Arrays.copyOf(arr1, arr1.length + arr2.length) 先扩,再用 System.arraycopy(arr2, 0, result, arr1.length, arr2.length) 补。这可行,但 copyOf 内部其实也调了一次 System.arraycopy,等于多一次初始化+拷贝。
立即学习“Java免费学习笔记(深入)”;
- 更直白写法是:先
new目标数组,再两次System.arraycopy -
Arrays.copyOfRange适合只取片段,不适合合并——它不拼接,只截 - 注意
Arrays.asList(...).toArray()不适用于基本类型数组,会把整个数组当一个元素装进去
最常被忽略的其实是目标数组的类型擦除问题:泛型数组无法直接 new,new T[n] 编译不过,这时候得用 Array.newInstance 或接受原始类型限制。这事一旦卡住,就容易绕到反射或 @SuppressWarnings("unchecked") 上去,反而埋下运行时风险。









