重点知识学习(7)--[对象克隆]
2022/1/16 23:38:10
本文主要是介绍重点知识学习(7)--[对象克隆],对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
关于对象克隆这部分,
在之前学习原型模式的时候有整理过一部分;
尚硅谷设计模式学习(5)— [原型模式(Prototype模式),深拷贝与浅拷贝]
文章目录
- 为什么要克隆
- 浅克隆(ShallowClone)
- 深克隆(DeepClone)
为什么要克隆
首先明白这样一个问题,它只是引用复制,而不是克隆
User user1 = new User(); User user2 = user1; User user3 = user1;
注意这样不是克隆;
是引用,即对象在内存中的地址,a 和 b 对象仍然指向了
同一个对象。这种只能称为引用复制,两个引用指向的还是同一个对象
案例
/** * @author by 信计1801 李智青 学号:1809064012 */ public class User { private String account; private Integer age; private String password; public User() { } public User(String account, Integer age, String password) { this.account = account; this.age = age; this.password = password; } public String getAccount() { return account; } public void setAccount(String account) { this.account = account; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } @Override public String toString() { return "User{" + "account='" + account + '\'' + ", age=" + age + ", password='" + password + '\'' + '}'; } }
测试
/** * @author by 信计1801 李智青 学号:1809064012 */ public class Test { public static void main(String[] args) { User user1 = new User("小智",22,"666666"); User user2 = user1; User user3 = user1; System.out.println(user1); System.out.println(user2); System.out.println(user3); System.out.println(user2 == user1); System.out.println(user3 == user2); } }
结果;实际上仅引用复制
User{account='小智', age=22, password='666666'} User{account='小智', age=22, password='666666'} User{account='小智', age=22, password='666666'} true true
之前写练习项目的时候,用户类中要关联其他的类;也是比较复杂的;
然后我们无论是从前端向后端发来请求的处理时数据,还有后端向后端处理响应时的数据,我们都用一个用户模型类去封装信息;这样的话,可能就会出现数据冗余的问题;
比如说:我这个用户类呢,它里面的属性比较多,账号,密码,性别,年龄,电话,地址,积分,比如说我现在只是要请求到用户的部分的数据,它里面就把所有的数据都包含进去了,即使没有数据,里面有的属性里面会自动赋值null传递出去;
Java中数据类型分为值类型(基本数据类型)和引用类型
- 值类型包括 int、double、byte、boolean、char 等简单数据类型,
- 引用类型包括类、接口、数组等复杂类型。
- 基本类型的值可以直接复制,引用类型只能复制引用地址。
- 浅克隆和深克隆的主要区别在于
是否支持引用类型的成员变量的复制
。
浅克隆(ShallowClone)
-
浅克隆中,如果原型对象的成员变量是
值类型
,将复制一份给克隆对象; -
如果原型对象的成员变量是
引用类型
,则将引用对象的地址复制一份给克隆对象
,也就是说原型对象和克隆对象的成员变量指向相同的内存地址
。 -
在浅克隆中,当
对象被复制时只复制它本身和其中包含的值类型的成员变量
,而引用类型的成员对象并没有复制
。
具体实现方式:
- 通过重写 Object 类的
clone()方法
可以实现浅克隆。 - 在 spring 框架中提供
BeanUtils.copyProperties(source,target)
案例
实现Cloneable
接口,重写clone方法试试
/** * @author by 信计1801 李智青 学号:1809064012 */ public class User implements Cloneable{ String account; Integer age; String password; public User() { } public User(String account, Integer age, String password) { this.account = account; this.age = age; this.password = password; } public String getAccount() { return account; } public void setAccount(String account) { this.account = account; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } @Override protected User clone() throws CloneNotSupportedException { User user = (User)super.clone(); return user; } @Override public String toString() { return "User{" + "account='" + account + '\'' + ", age=" + age + ", password='" + password + '\'' + '}'; } }
测试
/** * @author by 信计1801 李智青 学号:1809064012 */ public class Test { public static void main(String[] args) throws CloneNotSupportedException { User user1 = new User("小智",22,"666666"); User user2 = user1.clone(); System.out.println(user1); System.out.println(user2); System.out.println("----------地址是否相等-------------"); System.out.println(user2 == user1); System.out.println("----------hash值-------------"); System.out.println(user1.hashCode()); System.out.println(user2.hashCode()); } }
结果
User{account='小智', age=22, password='666666'} User{account='小智', age=22, password='666666'} ----------地址是否相等------------- false ----------hash值------------- 1265094477 2125039532
深克隆(DeepClone)
无论原型对象的成员变量是值类型还是引用类型,都将复制一份给克隆对象
,深克隆将原型对象的所有引用对象也复制一份给克隆对象。
- 对象所包含的所有成员变量也将复制。
- 如果需要实现深克隆,可以通过覆盖 Object 类的 clone()方法实现,也可以通过序列化(Serialization)等方式来实现。
序列化就是将对象写到流的过程,写到流中的对象是原有对象的一个拷贝,而原对象仍然存在于内存中。
通过序列化实现的拷贝不仅可以复制对象本身,而且可以复制其引用的成员对象,因此通过序列化将对象写到一个流中,再从流里将其读出来,可以实现深克隆。
需要注意的是能够实现序列化的对象其类必须实现Serializable 接口
,否则无法实现序列化操作。
案例:
在用户类User中关联了引用类型的属性班级类Grade;
/** * @author by 信计1801 李智青 学号:1809064012 */ public class Grade implements Cloneable{ private String name; public Grade() { } public Grade(String name) { this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "Grade{" + "name='" + name + '\'' + '}'; } @Override protected Grade clone() throws CloneNotSupportedException { return (Grade) super.clone(); } }
虽然,这个班级类已经重写了克隆方法;
但是,我在这用户类这边重写克隆方法时,仅克隆了引用类型Grade的地址
/** * @author by 信计1801 李智青 学号:1809064012 */ public class User implements Cloneable { String account; int age; //关联了班级类型; Grade grade; public User() { } public User(String account, int age) { this.account = account; this.age = age; } public String getAccount() { return account; } public void setAccount(String account) { this.account = account; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public Grade getGrade() { return grade; } public void setGrade(Grade grade) { this.grade = grade; } @Override public String toString() { return "User{" + "account='" + account + '\'' + ", age=" + age + ", grade=" + grade + '}'; } @Override protected User clone() throws CloneNotSupportedException { return (User)super.clone(); } }
测试
/** * @author by 信计1801 李智青 学号:1809064012 */ public class Test { public static void main(String[] args) throws CloneNotSupportedException { //首先创建了一个班级类对象; Grade grade = new Grade(); grade.setName("二年级"); //用户1; User user1 = new User("小智",22); user1.setGrade(grade); //用户2; User user2 = user1.clone(); user2.setAccount("杰哥"); grade.setName("大四"); System.out.println("用户1::"+user1); System.out.println("用户2::"+user2); } }
用户2在克隆时,仅克隆了地址
用户1::User{account='小智', age=22, grade=Grade{name='大四'}} 用户2::User{account='杰哥', age=22, grade=Grade{name='大四'}}
浅克隆
如果一个对象中关联了其他的引用变量, 浅克隆时,只会将关联的对象的引用地址复制出来,并没有创建一个新的对象.
那么稍微改变一下用户类User中重写的克隆方法
@Override protected User clone() throws CloneNotSupportedException { User user = (User)super.clone(); //深度复制; user.grade = grade.clone(); return user; }
测试结果
用户1::User{account='小智', age=22, grade=Grade{name='大四'}} 用户2::User{account='杰哥', age=22, grade=Grade{name='二年级'}}
深克隆
如果一个对象中关联了其他的引用变量, 深克隆时,将此对象中所关联的对象也会进行克隆操作,也就是会创建一个新的关联对象
序列化克隆的案例
班级类;
实现Serializable
接口
package com.xiaozhi.advanced.day07_objclone.objectClone.serializationclone; import java.io.Serializable; /** * @author by 信计1801 李智青 学号:1809064012 */ public class Grade implements Serializable { private String name; public Grade() { } public Grade(String name) { this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "Grade{" + "name='" + name + '\'' + '}'; } }
用户类实现Serializable
接口;
自定义克隆方法;
package com.xiaozhi.advanced.day07_objclone.objectClone.serializationclone; import java.io.*; /** * @author by 信计1801 李智青 学号:1809064012 */ public class User implements Serializable { String account; int age; //关联了班级类型; Grade grade; public User() { } public User(String account, int age) { this.account = account; this.age = age; } public String getAccount() { return account; } public void setAccount(String account) { this.account = account; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public Grade getGrade() { return grade; } public void setGrade(Grade grade) { this.grade = grade; } @Override public String toString() { return "User{" + "account='" + account + '\'' + ", age=" + age + ", grade=" + grade + '}'; } //自定义的克隆方法; public User customizeClone(){ User user = 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); user = (User) ois.readObject(); } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } return user; } }
测试
/** * @author by 信计1801 李智青 学号:1809064012 */ public class Test { public static void main(String[] args) throws CloneNotSupportedException { //首先创建了一个班级类对象; Grade grade = new Grade(); grade.setName("二年级"); //用户1; User user1 = new User("小智", 22); user1.setGrade(grade); //用户2; User user2 = user1.customizeClone(); user2.setAccount("杰哥"); grade.setName("大四"); System.out.println("用户1::" + user1); System.out.println("用户2::" + user2); } }
同样达到了深克隆的效果
用户1::User{account='小智', age=22, grade=Grade{name='大四'}} 用户2::User{account='杰哥', age=22, grade=Grade{name='二年级'}}
这篇关于重点知识学习(7)--[对象克隆]的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-23Springboot应用的多环境打包入门
- 2024-11-23Springboot应用的生产发布入门教程
- 2024-11-23Python编程入门指南
- 2024-11-23Java创业入门:从零开始的编程之旅
- 2024-11-23Java创业入门:新手必读的Java编程与创业指南
- 2024-11-23Java对接阿里云智能语音服务入门详解
- 2024-11-23Java对接阿里云智能语音服务入门教程
- 2024-11-23JAVA对接阿里云智能语音服务入门教程
- 2024-11-23Java副业入门:初学者的简单教程
- 2024-11-23JAVA副业入门:初学者的实战指南