一文读懂深克隆与浅克隆的关系(1)

文章讲述了Java中的super.clone()方法在对象复制时的浅克隆特性,以及如何通过序列化实现深克隆以避免引用对象共享的问题。作者还提供了示例代码和实际应用场景分析。

super.clone()方法直接从堆内存中以二进制流的方式进行复制,重新分配一个内存块,因此其效率很高。由于super.clone()方法基于内存复制,因此不会调用对象的构造函数,也就是不需要经历初始化过程。

在日常开发中,使用super.clone()方法并不能满足所有需求。如果类中存在引用对象属性,则原型对象与克隆对象的该属性会指向同一对象的引用。

@Data

public class ConcretePrototype implements Cloneable {

private int age;

private String name;

private List hobbies;

@Override

public ConcretePrototype clone() {

try {

return (ConcretePrototype)super.clone();

} catch (CloneNotSupportedException e) {

e.printStackTrace();

return null;

}

}

@Override

public String toString() {

return “ConcretePrototype{” +

“age=” + age +

“, name='” + name + ‘’’ +

“, hobbies=” + hobbies +

‘}’;

}

}

修改客户端测试代码。

public static void main(String[] args) {

//创建原型对象

ConcretePrototype prototype = new ConcretePrototype();

prototype.setAge(18);

prototype.setName(“Tom”);

List hobbies = new ArrayList();

hobbies.add(“书法”);

hobbies.add(“美术”);

prototype.setHobbies(hobbies);

System.out.println(prototype);

//复制原型对象

ConcretePrototype cloneType = prototype.clone();

cloneType.getHobbies().add(“技术控”);

System.out.println(“原型对象:” + prototype);

System.out.println(“克隆对象:” + cloneType);

}

我们给复制的对象新增一个属性hobbies(爱好)之后,发现原型对象也发生了变化,这显然不符合预期。因为我们希望复制出来的对象应该和原型对象是两个独立的对象,不再有联系。从测试结果来看,应该是hobbies共用了一个内存地址,意味着复制的不是值,而是引用的地址。这样的话,如果我们修改任意一个对象中的属性值,protoType 和cloneType的hobbies值都会改变。这就是我们常说的浅克隆。只是完整复制了值类型数据,没有赋值引用对象。换言之,所有的引用对象仍然指向原来的对象,显然不是我们想要的结果。那如何解决这个问题呢?

Java自带的clone()方法进行的就是浅克隆。而如果我们想进行深克隆,可以直接在super.clone()后,手动给复制对象的相关属性分配另一块内存,不过如果当原型对象维护很多引用属性的时候,手动分配会比较烦琐。因此,在Java中,如果想完成原型对象的深克隆,则通常使用序列化(Serializable)的方式。

2 使用序列化实现深克隆


在上节的基础上继续改造,增加一个deepClone()方法。

/**

  • Created by Tom.

*/

@Data

public class ConcretePrototype implements Cloneable,Serializable {

private int age;

private String name;

private List hobbies;

@Override

public ConcretePrototype clone() {

try {

return (ConcretePrototype)super.clone();

} catch (CloneNotSupportedException e) {

e.printStackTrace();

return null;

}

}

public ConcretePrototype deepClone(){

try {

ByteArrayOutputStream bos = new ByteArrayOutputStream();

ObjectOutputStream oos = new ObjectOutputStream(bos);

oos.writeObject(this);

ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());

ObjectInputStream ois = new ObjectInputStream(bis);

return (ConcretePrototype)ois.readObject();

}catch (Exception e){

e.printStackTrace();

return null;

}

}

@Override

public String toString() {

return “ConcretePrototype{” +

“age=” + age +

“, name='” + name + ‘’’ +

“, hobbies=” + hobbies +

‘}’;

}

}

客户端调用代码如下。

public static void main(String[] args) {

//创建原型对象

ConcretePrototype prototype = new ConcretePrototype();

prototype.setAge(18);

prototype.setName(“Tom”);

List hobbies = new ArrayList();

hobbies.add(“书法”);

hobbies.add(“美术”);

prototype.setHobbies(hobbies);

//复制原型对象

ConcretePrototype cloneType = prototype.deepCloneHobbies();

cloneType.getHobbies().add(“技术控”);

System.out.println(“原型对象:” + prototype);

System.out.println(“克隆对象:” + cloneType);

System.out.println(prototype == cloneType);

System.out.println(“原型对象的爱好:” + prototype.getHobbies());

System.out.println(“克隆对象的爱好:” + cloneType.getHobbies());

System.out.println(prototype.getHobbies() == cloneType.getHobbies());

}

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)

img

最后

很多程序员,整天沉浸在业务代码的 CRUD 中,业务中没有大量数据做并发,缺少实战经验,对并发仅仅停留在了解,做不到精通,所以总是与大厂擦肩而过。

我把私藏的这套并发体系的笔记和思维脑图分享出来,理论知识与项目实战的结合,我觉得只要你肯花时间用心学完这些,一定可以快速掌握并发编程。

不管是查缺补漏还是深度学习都能有非常不错的成效,需要的话记得帮忙点个赞支持一下

整理不易,觉得有帮助的朋友可以帮忙点赞分享支持一下小编~
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!
在业务代码的 CRUD 中,业务中没有大量数据做并发,缺少实战经验,对并发仅仅停留在了解,做不到精通,所以总是与大厂擦肩而过。

我把私藏的这套并发体系的笔记和思维脑图分享出来,理论知识与项目实战的结合,我觉得只要你肯花时间用心学完这些,一定可以快速掌握并发编程。

不管是查缺补漏还是深度学习都能有非常不错的成效,需要的话记得帮忙点个赞支持一下

整理不易,觉得有帮助的朋友可以帮忙点赞分享支持一下小编~
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值