深拷贝与浅拷贝的核心区别在于是否复制引用类型元素所指向的对象本身:浅拷贝仅复制数组容器及对象引用,导致新旧数组共享堆内存对象;深拷贝则为每个对象元素创建独立副本,实现完全隔离。

浅拷贝:只复制数组容器,不复制元素对象
浅拷贝创建新数组,但数组中若存的是对象引用,这些引用会被直接复制过去——新旧数组的对应位置指向同一个堆内存对象。
常见方式:
Arrays.copyOf(arr, arr.length)arr.clone()System.arraycopy(src, 0, dest, 0, length)- 直接用循环赋值:
dest[i] = src[i]
⚠️ 问题示例:
Person[] src = {new Person("Alice"), new Person("Bob")};
Person[] dest = Arrays.copyOf(src, src.length); // 浅拷贝
dest[0].setName("Charlie");
System.out.println(src[0].getName()); // 输出 "Charlie" —— 原数组被意外修改
深拷贝:每个元素对象都新建一份独立副本
深拷贝要求对数组中每个对象元素也执行克隆或重建,确保新数组与原数组在所有层级上完全隔离。
立即学习“Java免费学习笔记(深入)”;
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
可靠实现方式:
-
手动逐个克隆:前提是每个元素类实现了
Cloneable并重写clone() -
序列化反序列化:要求所有嵌套类实现
Serializable,适合复杂嵌套结构 -
JSON 工具转换(慎用):
new ObjectMapper().readValue(new ObjectMapper().writeValueAsString(arr), Person[].class),但会丢失非 JSON 友好类型(如Date、transient字段、方法等)
✅ 推荐手动克隆示例:
Person[] src = {new Person("Alice"), new Person("Bob")};
Person[] dest = new Person[src.length];
for (int i = 0; i < src.length; i++) {
dest[i] = src[i].clone(); // 要求 Person.clone() 是深拷贝实现
}
怎么判断该用哪种?看数组元素类型和后续操作
直接看数组内容:
- 全是
int[]、String[](String不可变)、Double[]等基本类型或不可变对象 → 浅拷贝足够 - 含自定义对象(如
Person[]、Order[]),且你要修改其字段(比如dest[0].setStatus("done"))→ 必须深拷贝 - 传给外部库(如 Spring Batch、Jackson 序列化、前端 JSON 接口)→ 默认按深拷贝处理,除非明确文档说明“只读”
验证是否真正深拷贝
改完拷贝数组后,立刻检查原数组对应路径:
- 执行
dest[0].setAge(99) - 紧接着
System.out.println(src[0].getAge()) - 输出不同 → 深拷贝成功;输出相同 → 还在共享引用,需更换实现方式

















