文章目录
前言
克隆的使用场景主要为需要将对象将源对象复制一份出来,保证后续改动不会对源对象造成影响。
浅克隆复制基本类型变量,改动克隆对象引用对象属性,会对源对象造成影响。
深克隆复制基本类型变量和引用类型变量,和源对象完全分割,改动克隆对象不会影响源对象。
一、浅克隆
1. 实体对象
package com.student.model;
/**
* Create by zjg on 2024/7/30
*/
public class Student {
private int id;
private String name;
private int age;
private String gender;
private Address address;
public Student() {
}
public Student(int id, String name, int age, String gender, Address address) {
this.id = id;
this.name = name;
this.age = age;
this.gender = gender;
this.address = address;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
", gender='" + gender + '\'' +
", address=" + address +
'}';
}
public static class Address implements Cloneable{
private String province;
private String city;
private String area;
public Address(String province, String city, String area) {
this.province = province;
this.city = city;
this.area = area;
}
public String getProvince() {
return province;
}
public void setProvince(String province) {
this.province = province;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public String getArea() {
return area;
}
public void setArea(String area) {
this.area = area;
}
@Override
public String toString() {
return "Address{" +
"province='" + province + '\'' +
", city='" + city + '\'' +
", area='" + area + '\'' +
'}';
}
}
}
2. 单元测试
package test.z202401;
import com.student.model.Student;
import org.springframework.beans.BeanUtils;
/**
* Create by zjg on 2024/7/30
*/
public class Test {
public static void main(String[] args) throws CloneNotSupportedException {
Student student=new Student(1,"张三",18,"男",new Student.Address("北京","北京","朝阳区"));
Student clone = new Student();
BeanUtils.copyProperties(student,clone);
System.out.println("修改前------");
System.out.println(student);
System.out.println(clone);
clone.setId(2);//修改克隆对象的id
clone.setName("李四");//修改克隆对象的名字
Student.Address address = clone.getAddress();
address.setProvince("山东省");//修改克隆对象的省
address.setCity("济南市");//修改克隆对象的市
address.setArea("市中区");//修改克隆对象的区
clone.setAddress(address);
System.out.println("修改后------");
System.out.println(student);
System.out.println(clone);
}
}
3. 输出
修改前------
Student{id=1, name='张三', age=18, gender='男', address=Address{province='北京', city='北京', area='朝阳区'}}
Student{id=1, name='张三', age=18, gender='男', address=Address{province='北京', city='北京', area='朝阳区'}}
修改后------
Student{id=1, name='张三', age=18, gender='男', address=Address{province='山东省', city='济南市', area='市中区'}}
Student{id=2, name='李四', age=18, gender='男', address=Address{province='山东省', city='济南市', area='市中区'}}
我们修改了克隆对象的
id
,name
和address
对象,对象1的id
和name
没有发生变化,但是对于我们自定义的Address
对象修改却影响了对象1的数据,可见它们使用的是同一个Address
对象。
二、深克隆
深度克隆有Cloneable和Serializable两种实现方式,都能解决上述问题,接下来我们逐个介绍
1. Cloneable
1.1 实体对象
package com.student.model;
/**
* Create by zjg on 2024/7/30
*/
public class Student implements Cloneable{
private int id;
private String name;
private int age;
private String gender;
private Address address;
public Student() {
}
public Student(int id, String name, int age, String gender, Address address) {
this.id = id;
this.name = name;
this.age = age;
this.gender = gender;
this.address = address;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
public Object clone() throws CloneNotSupportedException {
Student student = (Student)super.clone();
student.address = (Address)this.address.clone();
return student;
}
@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
", gender='" + gender + '\'' +
", address=" + address +
'}';
}
public static class Address implements Cloneable{
private String province;
private String city;
private String area;
public Address(String province, String city, String area) {
this.province = province;
this.city = city;
this.area = area;
}
public String getProvince() {
return province;
}
public void setProvince(String province) {
this.province = province;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public String getArea() {
return area;
}
public void setArea(String area) {
this.area = area;
}
public Object clone() throws CloneNotSupportedException {
Address address = (Address)super.clone();
return address;
}
@Override
public String toString() {
return "Address{" +
"province='" + province + '\'' +
", city='" + city + '\'' +
", area='" + area + '\'' +
'}';
}
}
}
1.2 单元测试
package test.z202401;
import com.student.model.Student;
/**
* Create by zjg on 2024/7/30
*/
public class Test {
public static void main(String[] args) throws CloneNotSupportedException {
Student student=new Student(1,"张三",18,"男",new Student.Address("北京","北京","朝阳区"));
Student clone = (Student)student.clone();
System.out.println("修改前------");
System.out.println(student);
System.out.println(clone);
clone.setId(2);//修改克隆对象的id
clone.setName("李四");//修改克隆对象的名字
Student.Address address = clone.getAddress();
address.setProvince("山东省");//修改克隆对象的省
address.setCity("济南市");//修改克隆对象的市
address.setArea("市中区");//修改克隆对象的区
clone.setAddress(address);
System.out.println("修改后------");
System.out.println(student);
System.out.println(clone);
}
}
1.3 输出
修改前------
Student{id=1, name='张三', age=18, gender='男', address=Address{province='北京', city='北京', area='朝阳区'}}
Student{id=1, name='张三', age=18, gender='男', address=Address{province='北京', city='北京', area='朝阳区'}}
修改后------
Student{id=1, name='张三', age=18, gender='男', address=Address{province='北京', city='北京', area='朝阳区'}}
Student{id=2, name='李四', age=18, gender='男', address=Address{province='山东省', city='济南市', area='市中区'}}
可以看出修改克隆对象的属性,不会对原对象造成影响
2. Serializable
2.1 实体对象
package com.student.model;
import java.io.Serializable;
/**
* Create by zjg on 2024/7/30
*/
public class Student implements Serializable {
private int id;
private String name;
private int age;
private String gender;
private Address address;
public Student() {
}
public Student(int id, String name, int age, String gender, Address address) {
this.id = id;
this.name = name;
this.age = age;
this.gender = gender;
this.address = address;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
", gender='" + gender + '\'' +
", address=" + address +
'}';
}
public static class Address implements Serializable {
private String province;
private String city;
private String area;
public Address(String province, String city, String area) {
this.province = province;
this.city = city;
this.area = area;
}
public String getProvince() {
return province;
}
public void setProvince(String province) {
this.province = province;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public String getArea() {
return area;
}
public void setArea(String area) {
this.area = area;
}
@Override
public String toString() {
return "Address{" +
"province='" + province + '\'' +
", city='" + city + '\'' +
", area='" + area + '\'' +
'}';
}
}
}
2.2 单元测试
package test.z202401;
import com.student.model.Student;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
/**
* Create by zjg on 2024/7/30
*/
public class Test {
public static void main(String[] args) throws IOException, ClassNotFoundException {
Student student=new Student(1,"张三",18,"男",new Student.Address("北京","北京","朝阳区"));
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(student);
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bais);
Student clone = (Student)ois.readObject();
System.out.println("修改前------");
System.out.println(student);
System.out.println(clone);
clone.setId(2);//修改克隆对象的id
clone.setName("李四");//修改克隆对象的名字
Student.Address address = clone.getAddress();
address.setProvince("山东省");//修改克隆对象的省
address.setCity("济南市");//修改克隆对象的市
address.setArea("市中区");//修改克隆对象的区
clone.setAddress(address);
System.out.println("修改后------");
System.out.println(student);
System.out.println(clone);
}
}
2.3 输出
修改前------
Student{id=1, name='张三', age=18, gender='男', address=Address{province='北京', city='北京', area='朝阳区'}}
Student{id=1, name='张三', age=18, gender='男', address=Address{province='北京', city='北京', area='朝阳区'}}
修改后------
Student{id=1, name='张三', age=18, gender='男', address=Address{province='北京', city='北京', area='朝阳区'}}
Student{id=2, name='李四', age=18, gender='男', address=Address{province='山东省', city='济南市', area='市中区'}}
实现序列化接口,通过对象流产生的对象也是不会对原对象产生影响。
总结
深度克隆的两种使用方式略有区别,大家可以根据自己的使用习惯来
实践是检验真理的唯一标准。