重点知识学习--[对象克隆]
Posted 小智RE0
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了重点知识学习--[对象克隆]相关的知识,希望对你有一定的参考价值。
关于对象克隆这部分,
在之前学习原型模式的时候有整理过一部分;
为什么要克隆
首先明白这样一个问题,它只是引用复制,而不是克隆
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);
结果;实际上仅引用复制
Useraccount='小智', age=22, password='666666'
Useraccount='小智', age=22, password='666666'
Useraccount='小智', 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());
结果
Useraccount='小智', age=22, password='666666'
Useraccount='小智', 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::Useraccount='小智', age=22, grade=Gradename='大四'
用户2::Useraccount='杰哥', age=22, grade=Gradename='大四'
浅克隆
如果一个对象中关联了其他的引用变量, 浅克隆时,只会将关联的对象的引用地址复制出来,并没有创建一个新的对象.
那么稍微改变一下用户类User中重写的克隆方法
@Override
protected User clone() throws CloneNotSupportedException
User user = (User)super.clone();
//深度复制;
user.grade = grade.clone();
return user;
测试结果
用户1::Useraccount='小智', age=22, grade=Gradename='大四'
用户2::Useraccount='杰哥', age=22, grade=Gradename='二年级'
深克隆
如果一个对象中关联了其他的引用变量, 深克隆时,将此对象中所关联的对象也会进行克隆操作,也就是会创建一个新的关联对象
序列化克隆的案例
班级类;
实现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;
以上是关于重点知识学习--[对象克隆]的主要内容,如果未能解决你的问题,请参考以下文章