前言
🐟缘由
Java对象拷贝:双胞胎还是影分身?深浅拷贝大揭秘!
想象一下,你和你的双胞胎兄弟共享同一套玩具,结果他把玩具车撞坏了,你瞬间心疼到怀疑人生——这就是浅拷贝的日常!而如果你们各自拥有独立的玩具仓库,那就是深拷贝的境界了。
今天,咱们就化身“克隆专家”,用双胞胎理论+影分身实战,彻底搞懂Java对象拷贝的那些事儿!保证看完后,再也不怕面试官问“深浅拷贝区别”!
🐣闪亮主角
一文搞懂Java对象深拷贝与浅拷贝
大家好,我是JavaDog程序狗。
今天我要像《X战警》里的“复制猫”一样,带你揭开对象拷贝的神秘面纱!从双胞胎共享玩具到独立仓库影分身,咱们一个不落!
正文
🎯主要目标
1. 什么是对象拷贝?
2. 浅拷贝 vs 深拷贝:双胞胎 vs 影分身
3. 浅拷贝的致命陷阱:共享对象的“连环爆炸”
4. 深拷贝的正确姿势:如何实现真正的“独立王国”
5. 代码实战:用玩具车和仓库演示深浅拷贝
🍪目标讲解
一. 对象拷贝:为什么需要克隆?
1. 白话理解
对象拷贝就像克隆一只宠物仓鼠。假设你有一只叫“小肥”的仓鼠,你想再“克隆”一只“小瘦”,但有两种玩法:
- 浅拷贝:小肥和小瘦共享同一个食盆,你给小肥加餐,小瘦也跟着饱了。
- 深拷贝:小肥和小瘦各自拥有独立的食盆,你喂谁都是喂自己。
2. 技术定义
对象拷贝是创建对象副本的过程。在Java中,拷贝分为浅拷贝和深拷贝,区别在于是否复制对象内部的引用类型成员。
二. 浅拷贝:双胞胎的“共享人生”
1. 浅拷贝的实现
// 浅拷贝实现:通过Cloneable接口
public class Person implements Cloneable {
private String name;
private Car car; // 引用类型
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone(); // 只拷贝基本类型和引用地址
}
}
2. 浅拷贝的致命问题
Person p1 = new Person("小明", new Car("Tesla"));
Person p2 = (Person) p1.clone();
p2.getCar().setBrand("比亚迪"); // 此时p1的car品牌也被改了!
问题:p1
和p2
共享同一个Car
对象,修改其中一个的引用对象会直接影响另一个!
三. 深拷贝:影分身的“独立王国”
1. 深拷贝的实现方式
方式一:序列化克隆
public class DeepCopyUtil {
public static <T extends Serializable> T deepCopy(T obj) {
try {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(obj);
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bis);
return (T) ois.readObject();
} catch (Exception e) {
throw new RuntimeException("深拷贝失败", e);
}
}
}
方式二:手动递归拷贝
public class Person implements Cloneable {
private String name;
private Car car;
@Override
protected Object clone() throws CloneNotSupportedException {
Person clone = (Person) super.clone();
clone.car = new Car(this.car.getBrand()); // 手动拷贝引用对象
return clone;
}
}
2. 深拷贝的优势
Person p1 = new Person("小明", new Car("Tesla"));
Person p2 = DeepCopyUtil.deepCopy(p1);
p2.getCar().setBrand("比亚迪"); // p1的car品牌保持不变!
四. 浅拷贝 vs 深拷贝:一场关于“独立”的辩论
特性 | 浅拷贝 | 深拷贝 |
---|---|---|
拷贝内容 | 基本类型 + 引用地址 | 基本类型 + 引用对象的独立副本 |
性能 | 高(只拷贝地址) | 低(需递归拷贝所有对象) |
适用场景 | 临时拷贝、性能敏感场景 | 数据隔离、修改不互相影响的场景 |
实现难度 | 低(实现Cloneable) | 高(需序列化或手动递归) |
五. 代码实战:用玩具车和仓库演示深浅拷贝
1. 场景:玩具店的“克隆风波”
class ToyCar {
private String brand;
private List<String> stickers; // 引用类型
// 省略getter/setter
}
class ToyStore {
private ToyCar bestSeller;
// 浅拷贝方法
public ToyStore shallowCopy() {
ToyStore copy = new ToyStore();
copy.bestSeller = this.bestSeller; // 共享同一个ToyCar对象!
return copy;
}
// 深拷贝方法(递归拷贝)
public ToyStore deepCopy() {
ToyStore copy = new ToyStore();
copy.bestSeller = new ToyCar();
copy.bestSeller.setBrand(this.bestSeller.getBrand());
copy.bestSeller.setStickers(new ArrayList<>(this.bestSeller.getStickers()));
return copy;
}
}
2. 实验结果
ToyStore store1 = new ToyStore(new ToyCar("乐高", Arrays.asList("闪电贴纸")));
ToyStore store2 = store1.shallowCopy();
store2.getBestSeller().getStickers().add("新贴纸"); // store1的贴纸也被修改了!
ToyStore store3 = store1.deepCopy();
store3.getBestSeller().setBrand("芭比"); // store1的品牌保持不变!
总结
Java对象拷贝分为浅拷贝和深拷贝。
浅拷贝仅复制对象的基本字段和引用地址,不复制引用对象本身,导致新旧对象共享引用类型数据(如修改car属性时两者同步变化)。其通过Cloneable接口实现,性能高但存在“共享修改”风险,适合临时拷贝或性能敏感场景。
深拷贝则复制对象及所有嵌套对象的独立副本,新旧对象完全隔离(修改深拷贝对象不影响原对象)。其实现方式包括序列化反序列化或手动递归拷贝,适用于需数据隔离的场景,但性能较低。
🍈猜你想问
如何与博主联系进行探讨
关注公众号【JavaDog程序狗】
公众号回复【入群】或者【加入】,便可成为【程序员学习交流摸鱼群】的一员,问题随便问,牛逼随便吹,目前群内已有超过380+个小伙伴啦!!!
2. 踩踩博主博客
里面有博主的私密联系方式呦 !,大家可以在里面留言,随意发挥,有问必答😘
🍯猜你喜欢
文章推荐
【实操】Spring Cloud Alibaba AI,阿里AI这不得玩一下(含前后端源码)
【项目实战】SpringBoot+uniapp+uview2打造H5+小程序+APP入门学习的聊天小项目
【项目实战】SpringBoot+uniapp+uview2打造一个企业黑红名单吐槽小程序
【模块分层】还不会SpringBoot项目模块分层?来这手把手教你!