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 方法就会很麻烦。这时我们可以用序列化的方式来实现对象的 深克隆。

相关内容

热门资讯

美众议员:若美国民众了解到有关... 据美国《纽约邮报》报道,美国共和党籍众议员蒂姆·伯切特当地时间4月1日接受采访时表示,如果美国民众了...
【观天下】涉嫌“战争罪” 美国... 涉嫌“战争罪” 美国百余名法律专家批对伊动武 王逸君 美国100多名国际法专家2日发表联名公开信,指...
小红书APP启用新品牌口号“你... 7月8日消息,小红书APP宣布新一轮品牌升级,启用品牌口号“你的生活兴趣社区”。用户更新版本后,新的...
中航沈飞:聘任王克喜为公司副总... 7月7日消息,中航沈飞晚间公告,公司第十届董事会第十六次会议审议通过了《关于聘任中航沈飞副总经理的议...
全球基金7月7日净买入32亿卢... 7月7日消息,据印度国家证券交易所(NSE),全球基金7月7日净买入32亿卢比印度股票。(科股宝播报...
理想汽车涨超5% 7月7日消息,理想汽车涨超5%,二季度累计销量11.1万辆,同比增长2.3%,环比增长19.6%,略...
梅赛德斯-奔驰集团二季度全球销... 7月7日消息,梅赛德斯-奔驰集团公布,2025年第二季度全球销售54.71万辆乘用车和轻型商用车,环...
中国工程机械工业协会:6月各类... 7月7日消息,据中国工程机械工业协会对挖掘机主要制造企业统计,2025年6月销售各类挖掘机18804...
ST凯利:涌金投资拟以5.18... 7月7日消息,ST凯利公告称,公司收到涌金投资控股有限公司发来的《上海凯利泰医疗科技股份有限公司要约...
蔚来与江淮汽车合资公司注销?知... 7月7日消息,今日一则关于蔚来汽车与江淮汽车合资公司注销的消息引发关注。从接近蔚来人士处得知,此次合...