JAVA对象克隆(为什么,如何实现,浅克隆和深克隆,解决多层克隆问题)
创始人
2025-05-28 11:12:02
0

对象克隆

    • 对象克隆
      • 1. 为什么要克隆?
      • 2 .如何实现克隆
      • 3. 浅克隆和深克隆
      • 4 .解决多层克隆问题

对象克隆

1. 为什么要克隆?

大家先思考一个问题,为什么需要克隆对象?直接 new 一个对象不行吗?

​ 克隆的对象可能包含一些已经修改过的属性,而 new 出来的对象的属性都还 是初始化时候的值,所以当需要一个新的对象来保存当前对象的“状态”就靠 clone 方法了。那么我把这个对象的临时属性一个一个的赋值给我新 new 的对 象不也行嘛?可以是可以,但是一来麻烦不说,二来,大家通过上面的源码都发 现了 clone 是一个 native 方法,就是快啊,在底层实现的

在实际的项目开发中从前端返回后端的数据我们一般都用一个Model来实现封装,而实际模型中同一个模型类又可分好几种,如专门负责接收前端数据的,可以加入验证. 向dao层传输数据的这里就需要用到对象的克隆.

误区:

我们常见的 Student stu1 = new Student ();

Student stu2 = stu1 ;

这种形式的代码复制的是引用,即对象在内存中的地址,

a 和 b 对象仍然指向了同一个对象。这种只能称为引用复制,两个引用指向的还是同一个对象.

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1FT2nlFL-1678864162937)(C:\Users\封纪元\AppData\Roaming\Typora\typora-user-images\1642636507625.png)]

2 .如何实现克隆

先介绍一下两种不同的克隆方法,浅克隆(ShallowClone)和深克隆(DeepClone)。 在 Java 语言中,数据类型分为值类型(基本数据类型)和引用类型,值类型包 括 int、double、byte、boolean、char 等简单数据类型,引用类型包括类、 接口、数组等复杂类型。基本类型的值可以直接复制,引用类型只能复制引用地 址。所以浅克隆和深克隆的主要区别在于是否支持引用类型的成员变量的复制。

3. 浅克隆和深克隆

1、浅克隆

在浅克隆中,如果原型对象的成员变量是值类型,将复制一份给克隆对象;如果原型对象的成员变量是引用类型,则将引用对象的地址复制一份给克隆对象,也 就是说原型对象和克隆对象的成员变量指向相同的内存地址。 简单来说,在浅克隆中,当对象被复制时只复制它本身和其中包含的值类型的成员变量,而引用类型的成员对象并没有复制

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JTcaguhM-1678864162938)(C:\Users\封纪元\AppData\Roaming\Typora\typora-user-images\1642636749606.png)]

一个浅克隆代码:

类及克隆代码

package objectClone.demo1;public class Person implements  Cloneable{int num;String name;public Person() {}public Person(int num, String name) {this.num = num;this.name = name;}public int getNum() {return num;}public void setNum(int num) {this.num = num;}public String getName() {return name;}public void setName(String name) {this.name = name;}@Overrideprotected Person clone() throws CloneNotSupportedException {Person person = (Person)super.clone();return person;}@Overridepublic String toString() {return "Person{" +"num=" + num +", name='" + name + '\'' +'}';}
}

测试

package objectClone.demo1;public class Test {public static void main(String[] args) throws CloneNotSupportedException {Person p1 = new Person(100,"jim");Person p2 =p1.clone();System.out.println(p1==p2);}
}

结果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-J3i0WUsC-1678864162939)(C:\Users\封纪元\AppData\Roaming\Typora\typora-user-images\1642637131998.png)]

2、深克隆

​ 在深克隆中,无论原型对象的成员变量是值类型还是引用类型,都将复制一份给克隆对象深克隆将原型对象的所有引用对象也复制一份给克隆对象简单来说,在深克隆中,除了对象本身被复制外,对象所包含的所有成员变量也将复制

​ 在 Java 语言中,如果需要实现深克隆,可以通过覆盖 Object 类的 clone()方法 实现,也可以通过序列化(Serialization)等方式来实现序列化就是将对象写到流的过程,写到流中的对象是原有对象的一个拷贝,而原对象仍然存在于内存中。通过序列化实现的拷贝不仅可以复制对象本身,而且可 以复制其引用的成员对象,因此通过序列化将对象写到一个流中,再从流里将其 读出来,可以实现深克隆。需要注意的是能够实现序列化的对象其类必须实现 Serializable 接口,否则无法实现序列化操作。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IUGCSNSH-1678864162939)(C:\Users\封纪元\AppData\Roaming\Typora\typora-user-images\1642637312505.png)]

深克隆clone代码实例:

引用类:

package objectClone.demo2;public class Address  implements Cloneable{String  address;public String getAddress() {return address;}public void setAddress(String address) {this.address = address;}@Overridepublic String toString() {return "Address{" +"address='" + address + '\'' +'}';}@Overrideprotected Address clone() throws CloneNotSupportedException {return (Address)super.clone();}
}

实体类:

package objectClone.demo2;public class Person implements  Cloneable{int num;String name;Address address;public Person() {}public Person(int num, String name) {this.num = num;this.name = name;}public int getNum() {return num;}public void setNum(int num) {this.num = num;}public String getName() {return name;}public void setName(String name) {this.name = name;}public Address getAddress() {return address;}public void setAddress(Address address) {this.address = address;}@Overrideprotected Person clone() throws CloneNotSupportedException {Person person = (Person)super.clone();person.address = (Address)address.clone();   //深度复制  联同person中关联的对象也一同克隆.return person;}@Overridepublic String toString() {return "Person{" +"num=" + num +", name='" + name + '\'' +", address=" + address +'}';}
}

测试:

package objectClone.demo2;public class Test {public static void main(String[] args) throws CloneNotSupportedException {Address address = new Address();address.setAddress("汉中");Person p1 = new  Person(100,"jim");p1.setAddress(address);Person p2 =p1.clone();p2.setName("tom");address.setAddress("西安");System.out.println(p1);System.out.println(p2);}
}

结果:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RpX2tp0e-1678864162939)(C:\Users\封纪元\AppData\Roaming\Typora\typora-user-images\1642637486717.png)]

​ 序列化方式代码实例:

引用类:

package objectClone.demo4;import java.io.Serializable;public class Address  implements Serializable {String  address;public String getAddress() {return address;}public void setAddress(String address) {this.address = address;}@Overridepublic String toString() {return "Address{" +"address='" + address + '\'' +'}';}}

实体类

package objectClone.demo4;import java.io.*;public class Person implements Serializable {int num;String name;Address address;public Person() {}public Person(int num, String name) {this.num = num;this.name = name;}public int getNum() {return num;}public void setNum(int num) {this.num = num;}public String getName() {return name;}public void setName(String name) {this.name = name;}public Address getAddress() {return address;}public void setAddress(Address address) {this.address = address;}/*** 自定义克隆方法* @return*/public Person myclone() {Person person = null;try { // 将该对象序列化成流,因为写在流里的是对象的一个拷贝,而原对象仍然存在于JVM里面。所以利用这个特性可以实现对象的深拷贝ByteArrayOutputStream baos = new ByteArrayOutputStream();ObjectOutputStream oos = new ObjectOutputStream(baos);oos.writeObject(this);// 将流序列化成对象ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());ObjectInputStream ois = new ObjectInputStream(bais);person = (Person) ois.readObject();} catch (IOException e) {e.printStackTrace();} catch (ClassNotFoundException e) {e.printStackTrace();}return person;}@Overridepublic String toString() {return "Person{" +"num=" + num +", name='" + name + '\'' +", address=" + address +'}';}
}

测试:

package objectClone.demo4;public class Test {public static void main(String[] args) throws CloneNotSupportedException {Address address = new Address();address.setAddress("汉中");Person p1 = new  Person(100,"jim");p1.setAddress(address);Person p2 =p1.myclone();p2.setName("tom");address.setAddress("西安");System.out.println(p1);System.out.println(p2);}
}

结果:

在这里插入图片描述

4 .解决多层克隆问题

如果引用类型里面还包含很多引用类型,或者内层引用类型的类里面又包含引用 类型,使用 clone 方法就会很麻烦。这时我们可以用序列化的方式来实现对象的 深克隆。

相关内容

热门资讯

2025年收官!北证50全年涨... 新京报贝壳财经讯(记者黄鑫宇)12月31日,北证市场迎来了2025年收官日。Wind显示,2025年...
创新科技金融服务驱动“科技—产... 2026年是“十五五”开局之年。坚持创新驱动,加紧培育壮大新动能,是2026年经济工作要抓好的重点任...
Kimi杨植麟:账上现金超10... 文 / 郭静来源 / 节点财经2025 年的岁末,当智谱 AI 与 MiniMax 相继在港股启动招...
资本市场投融资改革“动刀” |... 从“深化”到“持续深化”,资本市场投融资综合改革已连续两年跻身中央经济工作会议重点任务清单。这一表述...
基金经理转岗研究员,长城基金翁... 文 | 刘振涛长城基金一则基金经理卸任公告引来市场关注。近日,长城基金发布公告,旗下的长城久源灵活配...
万人空巷燃爆鹏城!开业前4小时... 导语:万人空巷燃爆鹏城!Olé Supermarket 12月31日焕新启幕,解锁“优品好价”品质生...
“再造新广州”,广州靠什么?专... 本文来源:时代周报 作者:曾思怡广州“十五五”规划建议提出,展望2035年,经济总量相较于2023年...
蓝箭航天科创板IPO获受理 拟... 【蓝箭航天科创板IPO获受理 拟融资75亿元】上交所官网显示,蓝箭航天空间科技股份有限公司科创板IP...
博道基金董事长莫泰山:2026... “预计2026年的A股市场仍将温和上涨,而其中不乏结构性机会。”2025年12月31日,博道基金董事...
这代人,不想急了 题图|视觉中国每一年的12月,品牌都会交上跨年的存在感作业,媒体也会反复上演相似的主题叙述:励志情绪...