Java 深复制与浅复制
Java里Object类有个方法clone(),访问类型是protected。该方法用于对对象的克隆。注意克隆不包含静态资源。
浅克隆(复制):浅复制只复制对象本身的8种基本数据类型及其他们的包装类型,不复制它所引用的对象本身。
深克隆(复制):复制对象的所有类型数据,相当于将对象本身数据及其对象中引用到的对象,在堆内存中重新写了一份。
从内存角度对浅复制和深复制进行表示,如下图所示:
举个例子来看一下浅复制:
/**
* Created by 杨Sir on 2017/11/17.
* 学生类
*/
public class Student implements Cloneable{
private Integer sId;
private String stuName;
private Teacher teacher;
public Student() {
}
public Student(Integer sId, String stuName, Teacher teacher) {
this.sId = sId;
this.stuName = stuName;
this.teacher = teacher;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
public Integer getsId() {
return sId;
}
public void setsId(Integer sId) {
this.sId = sId;
}
public String getStuName() {
return stuName;
}
public void setStuName(String stuName) {
this.stuName = stuName;
}
public Teacher getTeacher() {
return teacher;
}
public void setTeacher(Teacher teacher) {
this.teacher = teacher;
}
@Override
public String toString() {
return "Student{" +
"sId=" + sId +
", stuName='" + stuName + '\'' +
", teacher=" + teacher +
'}';
}
/**
* Created by 杨Sir on 2017/11/17.
* 教师类,供学生对象引用
*/
public class Teacher {
private int Id;
private String name;
private Integer age;
public Teacher() {
}
public Teacher(int id, String name, Integer age) {
Id = id;
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Teacher{" +
"Id=" + Id +
", name='" + name + '\'' +
", age=" + age +
'}';
}
public int getId() {
return Id;
}
public void setId(int id) {
Id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
}
/**
* Created by 杨Sir on 2017/11/17.
* 浅复制测试
*/
public class QianMain {
public static void main(String[] args) throws CloneNotSupportedException {
Teacher teacher = new Teacher(1001,"王老师",22);
Student student = new Student(1060001,"小明",teacher);
//打印原对象
System.out.println("原对象student:" + student);
//浅克隆student对象
Student studentClone = (Student) student.clone();
System.out.println("克隆对象studentClone:" + studentClone);
System.out.println("-------------------------------- \n");
//修改克隆对象的 基本类型数据和包装类型数据
studentClone.setsId(1060002);
studentClone.setStuName("杨小明");
//打印原对象和克隆对象,,根据结果我发现 Integer和String类型被进行了深复制。证明 8种基本类型,包装类型和String类型默认进行深复制
System.out.println("原对象student:" + student);
System.out.println("克隆对象studentClone:" + studentClone);
System.out.println("-------------------------------- \n");
//修改克隆对象的 引用类型数据
studentClone.getTeacher().setAge(21);
studentClone.getTeacher().setName("王Sir");
/**
* 打印原对象和克隆对象
* 原对象student:Student{sId=1060001, stuName='小明', teacher=Teacher{Id=1001, name='王Sir', age=21}}
* 克隆对象studentClone:Student{sId=1060002, stuName='杨小明', teacher=Teacher{Id=1001, name='王Sir', age=21}}
* 结果说明:对原对象中引用的对象进行了浅复制,相当于只复制了引用,两个引用指向同一个对象。
*/
System.out.println("原对象student:" + student);
System.out.println("克隆对象studentClone:" + studentClone);
}
}
如果我们希望克隆的对象能够独立于原对象,即深复制,那么我们有两种方法:
①. 深克隆(复制):对深克隆的理解前面已经描述过,此处不再赘述。
②. 序列化:序列化是通过通过将对象序列化为流进行传输,可以先存到磁盘中,然后在以反序列化的方式序列化出对象。
为了不使篇幅过长,深复制的完整代码和序列化进行深复制的完整代码在我的github中存放,地址是:https://github.com/yangSirKo/JavaCloneObject ,在案例中我详细注释了每一步的作用及结果,并且将序列化对象和反序列化对象封装为了工具类,在工具类中使用了静态的泛型方法,防止类型丢失以及类型转换异常。大家可以下载下来自己写一写~~ 喜欢就留个赞啦(github中点击Star哦)。