作为一个老牛马程序员,在编写代码的时候肯定遇到过对象需要克隆的问题,但是有时候比如说修改了克隆的副本以后,把原始数据也同步的给改了,这种情况还是挺烦人的,也可能不是我们要的效果。
为什么呢?因为克隆的时候它是分深拷贝和浅拷贝两种情况的,接下来我们就这两种情况进行一个好好的分析!
一、技术核心:堆内存中的对象真相
Java对象在内存中分两部分存储:
java
Person person1 = new Person("张三", new Address("北京"));
person1
变量本身(对象引用)存在栈内存- 实际包含数据(name="张三", address对象)存在堆内存
二、浅拷贝:只复制第一层
浅拷贝只复制原始对象本身,不复制其引用的其他对象。新老对象共享内部引用对象。
实现方式1:默认的clone()方法
java
HardwareParameters implements Cloneable {
String name;
Address address; // 引用类型
//重写clone()方法,因为它是的类型是protected的
@Override
public HardwareParameters clone() throws CloneNotSupportedException {
return (HardwareParameters) super.clone();
}
}
public static void main(String[] args) throws CloneNotSupportedException {
HardwareParameters hardwareParameters1 = new HardwareParameters("柜体尺寸", new CaseList("这是第一个呀"));
//调用重写的clone方法
HardwareParameters hardwareParameters2 = (HardwareParameters) hardwareParameters1.clone();
//修改拷贝后的参数
hardwareParameters2.getCaseList().setTitle("这是第二个呀");
System.out.println("hardwareParameters2的值:"+hardwareParameters2.getCaseList().getTitle());
System.out.println("hardwareParameters1的值: "+hardwareParameters1.getCaseList().getTitle());
}

实现方式2:Maven中的BeanUtils类

那么什么时候使用:
- 只包含基本类型的DTO对象传输
- 临时对象快照(确保不修改原始对象的基础属性)
- 配合不可变对象(如String)使用
四、深拷贝:
深拷贝会递归复制所有层级的对象,生成一个完全独立的对象网络。
实现方式:特别简单直接使用JSON序列化
java
public static void main(String[] args) {
Gson gson = new Gson();
HardwareParameters hardwareParameters1 = new HardwareParameters("柜体尺寸", new CaseList("这是第一个呀"));
// HardwareParameters hardwareParameters2 = new HardwareParameters();
HardwareParameters hardwareParameters2 = gson.fromJson(gson.toJson(hardwareParameters1), HardwareParameters.class);
// BeanUtils.copyProperties(hardwareParameters1, hardwareParameters2);
//修改拷贝后的参数
hardwareParameters2.getCaseList().setTitle("这是第二个呀");
System.out.println("hardwareParameters2的值:"+hardwareParameters2.getCaseList().getTitle());
System.out.println("hardwareParameters1的值: "+hardwareParameters1.getCaseList().getTitle());
}
}

那么什么时候使用:
- 需要修改副本且不影响原始对象的场景(如缓存数据更新)
- 复杂对象图的版本快照
- 多线程环境下共享数据的安全隔离
- 游戏开发中的状态保存/恢复
五、关键决策:如何选择拷贝方式?
根据我的项目经验,遵循以下原则能避开90%的坑:
- 对象结构简单 → 优先考虑浅拷贝
- 包含嵌套可变对象 → 必须深拷贝
- 性能敏感 → 浅拷贝速度更快(深拷贝递归消耗大)
- 网络传输或持久化 → 序列化实现深拷贝最可靠
总结关键知识点
特性 | 浅拷贝 | 深拷贝 |
---|---|---|
复制深度 | 仅第一层对象 | 所有层级对象 |
引用对象处理 | 共享引用 | 创建新对象 |
实现复杂度 | 简单(默认clone即可) | 复杂(需递归或序列化) |
数据隔离性 | 弱(修改影响原对象) | 强(完全独立) |
下次遇到对象复制需求时,不妨先问自己:此处需要的是复印件,还是完全独立的副本?答案自然就很清晰了。