Java数组拷贝问题多表现为运行时异常或静默错误,根源在于System.arraycopy严格校验参数且仅做浅拷贝;需区分引用赋值与真实复制,用clone()、Arrays.copyOf()或正确配置System.arraycopy,并检查空指针、负数及越界参数。

Java 数组拷贝出问题,往往不是编译报错,而是运行时行为“不对劲”:改了副本,原数组跟着变;拼接后数据错位;扩容多出的元素是 0 或 null 却没察觉;一调用就抛异常,但看不出哪错了。核心在于 System.arraycopy 不容错、不兜底,它只忠实地按你给的数字搬运内存块——参数错一点,立刻崩溃或静默出错。
确认是否真在“复制”,而非引用赋值
写成 int[] b = a 或 String[] copy = original,根本没复制,只是让两个变量指向同一块内存。后续任何修改都会互相影响,表面无异常,实则逻辑已崩。
- 排查方法:打印
System.identityHashCode(a)和System.identityHashCode(b),结果相同说明是同一对象 - 真正复制应选:
a.clone()、Arrays.copyOf(a, a.length),或用System.arraycopy配合新分配的目标数组 - 注意:所有这些方式对引用类型数组都只做浅拷贝——数组里存的是对象地址,不是对象本身
校验三类硬性参数边界
System.arraycopy 的五个参数中,只要一个越界或非法,就会立即抛异常。不是“执行中发现才报”,而是在入口统一检查后直接中断。
-
空指针:src 或 dest 为 null,第一时间抛
NullPointerException,比索引检查还早 -
负数参数:srcPos、destPos 或 length 小于 0,抛
IndexOutOfBoundsException(JVM 实际抛的是NegativeArraySizeException当 length -
越界长度:必须同时满足
srcPos + length ≤ src.length且destPos + length ≤ dest.length,否则抛IndexOutOfBoundsException
建议在调用前显式校验,或封装成带校验的工具方法,避免每次手写 if 漏判。
立即学习“Java免费学习笔记(深入)”;
区分浅拷贝陷阱与类型不兼容风险
基本类型数组(如 int[])拷贝后完全独立;但引用类型数组(如 Person[])默认只复制引用地址,这是浅拷贝。
- 验证方式:用
==比较两个数组对应位置的对象,若返回 true,说明是同一实例 - 若需深拷贝,不能只拷数组,还要逐个 clone 对象或 new 新实例(需类支持)
- 类型不匹配会抛
ArrayStoreException:例如把 String[] 往 Integer[] 拷,或 Object[](含多种类型)往 String[] 拷,遇到第一个不兼容元素即中断 - 该异常无法编译期发现,运行时才暴露,务必确保目标数组类型能容纳源元素
拼接、截取与原地移位的参数要点
拼接和截取不是语法糖,本质是分段搬运,参数顺序和偏移量极易填反。
-
拼接两数组:目标数组长度 = a.length + b.length;第二段拷贝的
destPos必须是a.length,不是 0 或 b.length -
截取一段:目标数组必须提前 new 好,长度 ≥ 要拷的个数;
srcPos是下标,不是字节偏移 -
原地移位:当 src == dest 时,JVM 自动识别重叠并选择正向/倒序搬运——但前提是参数合法;方向由
srcPos和destPos大小关系决定,不能靠猜 - length = 0 是合法操作,可用于边界预检,不触发实际搬运
别用 for 循环模拟 arraycopy——它的底层是 memmove 或 SIMD 指令,手写不仅慢,还容易覆盖出错。


















