引用类型数组默认是浅拷贝,只复制引用地址而非对象本身;深拷贝需手动实现,如克隆、序列化或构造新对象;基本类型数组拷贝的是值,天然独立。

Java 数组拷贝中,引用类型数组的“引用拷贝”和“内容拷贝”根本不是一回事:前者只复制地址,后者才真正复制对象数据。关键不在怎么写代码,而在你是否清楚自己到底想隔离数据,还是只想共享对象。
引用类型数组的默认拷贝是浅拷贝
用 System.arraycopy、Arrays.copyOf 或 clone() 拷贝 String[]、User[] 等引用类型数组时,实际复制的是每个元素的引用(内存地址),不是对象本身。
- 两个数组长度相同、索引一一对应,但所有元素指向堆中同一组对象
- 修改
arr2[0].setName("新名字"),arr1[0]的名字也会变——因为它们是同一个 User 实例 - String 是特例:它不可变,
arr2[0] = "hello"只是让 arr2[0] 指向新字符串,不影响 arr1[0],但这属于赋值行为,不是拷贝逻辑带来的效果
内容拷贝 = 深拷贝,必须手动实现
要让新数组里的对象和原数组完全独立,就得对每个元素做深拷贝。没有通用一行代码能搞定,取决于对象是否支持克隆或序列化。
Java Maven 项目审查工作流的通用输入处理。当 Java Maven 项目以 ZIP压缩包或 GitLab 仓库 URL 形式提供且需要...时使用。
- 若元素类实现了
Cloneable且重写了clone()(并确保内部引用也 clone),可遍历调用:dest[i] = (T) src[i].clone() - 若类实现了
Serializable,可用序列化方式:把整个数组对象写入字节流再读出,天然递归深拷贝(注意性能开销和 transient 字段) - 最稳妥但略繁琐的方式:用构造函数逐个新建对象,例如
dest[i] = new User(src[i].getName(), src[i].getAge())
基本类型数组不存在这个问题
int[]、double[] 这类数组拷贝后,源与目标彻底无关——因为拷贝的是数值本身,不是地址。
-
System.arraycopy对基本类型就是值拷贝,安全高效 - 改
dest[0] = 99,src[0]完全不受影响 - 所以别把基本类型的经验套到引用类型上,这是最容易踩的坑
怎么选?看你的业务意图
拷贝不是技术动作,而是数据契约。问自己一句:这个副本要不要和原件“解耦”?
- 只是临时读取、不修改对象内容 → 浅拷贝足够,快且省内存
- 要并发修改、做状态快照、防止副作用 → 必须深拷贝,哪怕多写几行
- 不确定?先用
System.identityHashCode(obj)打印几个元素的哈希码,对比源数组和目标数组同位置元素是否一致,一眼验证是浅是深
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










