1、引用拷贝:拷贝的是引用,但是源和复制都指向同一个对象
2、浅拷贝:源和复制的所有变量值都相同,但是仅仅拷贝的是源对象,源对象里的引用所指向的对象并没有被拷贝。
3、深拷贝:深拷贝会拷贝源对象的所有属性,并拷贝属性指向的动态分配的内存,也就是说拷贝源对象以及源对象里引用所指向的对象。
示例代码:
1、教师类:
package clone;
import java.io.Serializable;
public class Teacher implements Cloneable,Serializable {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
2、学生类:
package clone;
import java.io.*;
public class Student implements Cloneable,Serializable {
private String name;
private Teacher teacher;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Teacher getTeacher() {
return teacher;
}
public void setTeacher(Teacher teacher) {
this.teacher = teacher;
}
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
public Student deepClone1() throws CloneNotSupportedException {
Student student = (Student) super.clone();
Student s3 = student;
s3.setTeacher((Teacher) student.getTeacher().clone());
return s3;
}
public Object deepClone2() throws Exception {
// 序列化
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(this);
// 反序列化
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bis);
return ois.readObject();
}
}
3、测试类:
package clone;
public class TestClone {
public static void main(String[] args) throws Exception {
//引用拷贝
Teacher t1 = new Teacher();
t1.setName("张老师");
Student s1 = new Student();
s1.setName("李同学");
s1.setTeacher(t1);
Student s2 = s1;
System.out.println("*****************引用拷贝*********************");
System.out.println(s1);
System.out.println(s2);
System.out.println("*****************引用拷贝*********************\n");
//浅拷贝
Student s3 = (Student) s1.clone();
System.out.println("*****************浅拷贝*********************");
System.out.println(s1);
System.out.println(s3);
System.out.println(s1.getTeacher());
System.out.println(s3.getTeacher());
System.out.println("*****************浅拷贝*********************\n");
//深拷贝1
Student s4 = s1.deepClone1();
System.out.println("*****************深拷贝1*********************");
System.out.println(s1);
System.out.println(s4);
System.out.println(s1.getTeacher());
System.out.println(s4.getTeacher());
System.out.println("*****************深拷贝1*********************\n");
//深拷贝2
Student s5 = (Student)s1.deepClone2();
System.out.println("*****************深拷贝2*********************");
System.out.println(s1);
System.out.println(s5);
System.out.println(s1.getTeacher());
System.out.println(s5.getTeacher());
System.out.println("*****************深拷贝2*********************\n");
}
}
4、运行结果:
5、结果分析:
1)、引用拷贝中,源对象和复制对象的引用指向的是同一个对象,所以打印出来的地址也相同
2)、浅拷贝中,可通过 Cloneable 类的 clone() 方法进行浅拷贝。从打印出来的日志看,源对象和复制对应的引用地址是不一样的,但是对象里面的教师对象的引用地址是一样的,这是不彻底的拷贝
3)、深拷贝中,有两种实现方式:
a、重写 Cloneable.clone() 方法,克隆源对象的同时,把里面的对象也克隆。
b、重写 Cloneable.clone() 方法,利用序列化进行深拷贝,把源对象写入一个字节流中,然后再将其读出,则可创建一个新的对象,并且该新对象与源对象之间并不存在引用共享的问题,真正实现对象的深拷贝。
从打印的日志来看,深拷贝1和深拷贝2的源对象和复制对象、源对象里的对象和复制对象里的对象引用地址均不相同,说明实现了深拷贝。