浅拷贝和深拷贝
- 引用的复制:不同的引用指向同一个对象
- 浅复制:只复制当前对象,若对象当中还有其他的引用则不复制
- 深复制:复制出一个全新的对象,包括里面所有的引用数据类型
下面我们通过代码来理解一下复制的概念
1. 引用的拷贝
//有一个简单的老师类
public class Teacher{
//姓名
private Sting name;
//年龄
private int age;
//----省去构造方法和getter、setter---------//
}
//引用的复制
@Test
public void test1(){
Teacher tea1 = new Teacher("方老师", 16);
Teacher tea2 = tea1;
System.out.println(tea1 == tea2);//true
//指向的是堆中的同一个对象
}
2. 浅拷贝:
//老师类
//实现标识性接口,让类具有复制的能力
public class Teacher implements Cloneable{
private String name;
private int age;
//有一个学生的对象
private Student student;
//----省去构造方法和getter、setter---------//
//重写Object类的clone方法,修改访问修饰符为public
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
//学生类
public class Student implements Cloneable{
private String name;
private int age;
//----省去构造方法和getter、setter---------//
//重写Object类的clone方法,修改访问修饰符为public
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
//实现浅复制
public void test2(){
Student stu1 = new Student("阿文", 18);
Teacher tea = new Teacher("方老师", 16, stu1);
//复制对象,向下转型
Teacher tea_clone = (Teacher)tea.clone();
System.out.println(tea == tea_clone);//false
//在堆中划分了一个新的对象指向了这个引用
System.out.println(tea.student == tea_clone.student)//true对象中的引用数据类型指向的还是堆中的同一个对象
}
3. 深拷贝
//以上面的老师类和学生类为基础,我们需要重写clone()方法的方法体
public class Teacher implements Cloneable{
private String name;
private int age;
//有一个学生的对象
private Student student;
//----省去构造方法和getter、setter---------//
//重写Object类的clone方法,修改访问修饰符为public
@Override
public Object clone() throws CloneNotSupportedException {
Teacher teacher = (Teacher)super.clone();
teacher.sudent = (Student)student.clone();
return teacher;
}
}
public void test3(){
Student stu1 = new Student("阿文", 18);
Teacher tea = new Teacher("方老师", 16, stu1);
//复制对象,向下转型
Teacher tea_clone = (Teacher)tea.clone();
System.out.println(tea == tea_clone);//false
//在堆中划分了一个新的对象指向了这个引用
System.out.println(tea.student == tea_clone.student)//false,可以看到我们实现了将该对象的彻底复制
}
//如果引用数据类型存放的是List集合,同理要将List复制一遍,再把里面存放的所有对象复制一遍
public Object clone() throws CloneNotSupportedException {
Teacher teacher = (Teacher) super.clone();
ArrayList<Student> students = new ArrayList<>();
for (Student stu : teacher.student) {
students.add((Student) stu.clone);
}
teacher.student = students;
return teacher;
}
4. 使用序列化的方式实现拷贝
以上演示的是使用clone()的方法实现深复制,我们同样可以使用序列化反序列化实现深复制
//教师类实现序列化的接口
public class Teacher implements Serializable{
private String name;
private int age;
//有一个学生的对象
private Student student;
//----省去构造方法和getter、setter---------//
public Object deepClone() throws IOException, ClassNotFoundException {
//创建字节数组型的字节输出流
ByteArrayOutputStream bos = new ByteArrayOutputStream();
//序列化
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(this);
//反序列化
ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(bos.toByteArray());
return ois.readObject();
}
}
//学生类,实现序列化的接口
public class Student implements Serializable{
private String name;
private int age;
//----省去构造方法和getter、setter---------//
}
@Test
public void test4(){
Student stu1 = new Student("阿文", 18);
Teacher tea = new Teacher("方老师", 16, stu1);
//复制对象,向下转型
Teacher tea_clone = (Teacher)tea.deepClone();
System.out.println(tea == tea_clone);//false
//在堆中划分了一个新的对象指向了这个引用
System.out.println(tea.student == tea_clone.student)//false,可以看到我们实现了将该对象的彻底复制
}