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

相关内容

热门资讯

研究成果!微乐小程序黑科技免费... 研究成果!微乐小程序黑科技免费(辅助器),小程序微乐陕西挖坑辅助(果真有辅助挂)1、游戏颠覆性的策略...
避坑细节!微乐小程序免费黑科技... 避坑细节!微乐小程序免费黑科技(辅助),微信小程序微乐辅助免费(有辅助挂讲解)1、任何微乐小程序免费...
普及知识!微乐小程序辅助工具(... 普及知识!微乐小程序辅助工具(辅助器),微信小程序微乐辅助器破解版(有辅助挂详情)1.微乐小程序辅助...
必备教程!微乐小程序免费黑科技... 必备教程!微乐小程序免费黑科技(作弊器),小程序微乐贵阳捉鸡麻将挂(有辅助挂秘籍)1、操作简单,无需...
一起来探讨!微乐小程序免费黑科... 一起来探讨!微乐小程序免费黑科技(辅助),微乐河南小程序微乐辅助脚本(有辅助挂工具)1、让任何用户在...
分享一款!微乐小程序免费黑科技... 分享一款!微乐小程序免费黑科技(辅助),小程序微乐游戏辅助器(有辅助挂神器)1、不需要AI权限,帮助...
玩家必看分享!微乐小程序辅助工... 玩家必看分享!微乐小程序辅助工具(透视挂),微乐小程游戏破解器下载(有辅助挂教程)1、不需要AI权限...
玩家爆料!微乐小程序黑科技免费... 玩家爆料!微乐小程序黑科技免费(透视器),微乐智能辅助app(有辅助挂神器)微乐小程序黑科技免费能透...
一分钟了解!微乐小程序黑科技免... 一分钟了解!微乐小程序黑科技免费(外挂),微乐河南麻将辅助ios(有挂辅方法)1)微乐小程序黑科技免...
我来教教你!微乐小程序免费黑科... 我来教教你!微乐小程序免费黑科技(外挂),微信小程序可以开挂吗(竟然有辅助挂)1、微乐小程序免费黑科...