一、拷贝的引入

Ⅰ、引用拷贝

创建一个指向对象的引用变量的拷贝:

  1. @Data
  2. public class Teacher {
  3. private String name;
  4. private int age;
  5. public Teacher(String name, int age) {
  6. this.name = name;
  7. this.age = age;
  8. }
  9. }
  1. public class Client {
  2. public static void main(String[] args) {
  3. Teacher teacher_1 = new Teacher("greamrod", 27);
  4. Teacher teacher_2 = teacher_1;
  5. System.out.println("teacher_1 = " + teacher_1);
  6. System.out.println("teacher_2 = " + teacher_2);
  7. System.out.println("teacher_1 == teacher_2 --> " + (teacher_1 == teacher_2));
  8. }
  9. }

输出如下:

  1. teacher_1 = Teacher(name=greamrod, age=27)
  2. teacher_2 = Teacher(name=greamrod, age=27)
  3. teacher_1 == teacher_2 --> true

由输出结果teacher_1 == teacher_2 --> true可以看出,它们的地址值是相同的,那么它们肯定是同一个对象。teacher_1teacher_2的只是引用而已,他们都指向了一个相同的对象new Teacher("greamrod", 27)。 这就叫做引用拷贝
原型模式 - 图1

Ⅱ、对象拷贝

使用原型模式,创建对象本身的一个副本:

  1. @Data
  2. public class Teacher implements Cloneable {
  3. private String name;
  4. private int age;
  5. public Teacher(String name, int age) {
  6. this.name = name;
  7. this.age = age;
  8. }
  9. public Teacher clone() throws CloneNotSupportedException {
  10. Teacher object = (Teacher) super.clone();
  11. return object;
  12. }
  13. }
  1. public class Client {
  2. public static void main(String[] args) throws CloneNotSupportedException {
  3. Teacher teacher_1 = new Teacher("greamrod", 27);
  4. Teacher teacher_2 = teacher_1.clone();
  5. System.out.println("teacher_1 = " + teacher_1);
  6. System.out.println("teacher_2 = " + teacher_2);
  7. System.out.println("teacher_1 == teacher_2 --> " + (teacher_1 == teacher_2));
  8. }
  9. }

输入如下:

  1. teacher_1 = Teacher(name=greamrod, age=27)
  2. teacher_2 = Teacher(name=greamrod, age=27)
  3. teacher_1 == teacher_2 --> false

由输出结果teacher_1 == teacher_2 --> false可以看出,它们的地址是不同,也就是说创建了新对象, 而不是把原对象的地址赋给了一个新的引用变量,这就叫做对象拷贝
原型模式 - 图2

二、浅拷贝

概念:

  • ①:对于数据类型是基本数据类型的成员变量:浅拷贝会直接进行值传递,也就是将该属性值复制一份给新的对象。
  • ②:对于数据类型是引用数据类型的成员变量:例如成员变量是某个数组、某个类的对象等,那么浅拷贝会进行引用传递,也就是只是将该成员变量的引用值(内存地址)复制一份给新的对象。因为实际上两个对象的各自成员变量都指向同一个实例。在这种情况下,在一个对象中修改自身成员变量,会影响到另一个对象的该成员变量值。

实现方式:

  • ①:使用默认cloen()方法来实现深拷贝。
  1. @Data
  2. public class Teacher {
  3. private String name;
  4. private int age;
  5. public Teacher(String name, int age) {
  6. this.name = name;
  7. this.age = age;
  8. }
  9. }
  1. @Data
  2. public class Student implements Cloneable {
  3. private String name;
  4. private int age;
  5. private Teacher teacher;
  6. public Student(String name, int age, Teacher teacher) {
  7. this.name = name;
  8. this.age = age;
  9. this.teacher = teacher;
  10. }
  11. public Object clone() throws CloneNotSupportedException {
  12. Object object = super.clone();
  13. return object;
  14. }
  15. }
  1. public class Client {
  2. public static void main(String[] args) throws CloneNotSupportedException {
  3. Teacher teacher = new Teacher("greamrod", 27);
  4. Student student_1 = new Student("jack", 10, teacher);
  5. Student student_2 = (Student) student_1.clone();
  6. System.out.println("student_1 = " + student_1);
  7. System.out.println("student_2 = " + student_2);
  8. System.out.println("student_1 == student_2 --> " + (student_1 == student_2));
  9. System.out.println("\n-------------修改老师的信息后-------------");
  10. teacher.setName("peter");
  11. teacher.setAge(50);
  12. System.out.println("student_1 = " + student_1);
  13. System.out.println("student_2 = " + student_2);
  14. System.out.println("student_1 == student_2 --> " + (student_1 == student_2));
  15. }
  16. }

输出如下:

  1. student_1 = Student(name=jack, age=10, teacher=Teacher(name=greamrod, age=27))
  2. student_2 = Student(name=jack, age=10, teacher=Teacher(name=greamrod, age=27))
  3. student_1 == student_2 --> false
  4. -------------修改老师的信息后-------------
  5. student_1 = Student(name=jack, age=10, teacher=Teacher(name=peter, age=50))
  6. student_2 = Student(name=jack, age=10, teacher=Teacher(name=peter, age=50))
  7. student_1 == student_2 --> false

结果分析,两个引用student_1student2分别指向,两个不同Student对象。但两个Student对象的teacher成员变量的引用,指向的是同一个对象,所以说明是浅拷贝
原型模式 - 图3

三、深拷贝

概念:

  • ①:复制对象的所有基本数据类型的成员变量
  • ②:为所有引用数据类型的成员变量申请存储空间,并复制每个引用数据类型成员变量所指向的对象,直到该对象可达的所有对象。也就是说,对象进行深拷贝,要对整个对象进行拷贝。

实现方式:

  • ①:重写cloen()方法来实现深拷贝,对象中所有引用数据类型都要实现Cloneable接口。
  • ②:通过对象序列化、反序列化实现深拷贝。

Ⅰ、重写cloen()方法来实现深拷贝

代码如下:

  1. @Data
  2. public class Teacher implements Cloneable {
  3. private String name;
  4. private int age;
  5. public Teacher(String name, int age) {
  6. this.name = name;
  7. this.age = age;
  8. }
  9. @Override
  10. protected Object clone() throws CloneNotSupportedException {
  11. return super.clone();
  12. }
  13. }
  1. @Data
  2. public class Student implements Cloneable {
  3. private String name;
  4. private int age;
  5. private Teacher teacher;
  6. public Student(String name, int age, Teacher teacher) {
  7. this.name = name;
  8. this.age = age;
  9. this.teacher = teacher;
  10. }
  11. public Object clone() throws CloneNotSupportedException {
  12. Student student = (Student) super.clone();
  13. Teacher teacher = (Teacher) student.teacher.clone();
  14. student.setTeacher(teacher);
  15. return student;
  16. }
  17. }
  1. public class Client {
  2. public static void main(String[] args) throws CloneNotSupportedException {
  3. Teacher teacher = new Teacher("greamrod", 27);
  4. Student student_1 = new Student("jack", 10, teacher);
  5. Student student_2 = (Student) student_1.clone();
  6. System.out.println("student_1 = " + student_1);
  7. System.out.println("student_2 = " + student_2);
  8. System.out.println("student_1 == student_2 --> " + (student_1 == student_2));
  9. System.out.println("\n-------------修改老师的信息后-------------");
  10. teacher.setName("peter");
  11. teacher.setAge(50);
  12. System.out.println("student_1 = " + student_1);
  13. System.out.println("student_2 = " + student_2);
  14. System.out.println("student_1 == student_2 --> " + (student_1 == student_2));
  15. }
  16. }

输出如下:

  1. student_1 = Student(name=jack, age=10, teacher=Teacher(name=greamrod, age=27))
  2. student_2 = Student(name=jack, age=10, teacher=Teacher(name=greamrod, age=27))
  3. student_1 == student_2 --> false
  4. -------------修改老师的信息后-------------
  5. student_1 = Student(name=jack, age=10, teacher=Teacher(name=peter, age=50))
  6. student_2 = Student(name=jack, age=10, teacher=Teacher(name=greamrod, age=27))
  7. student_1 == student_2 --> false

两个引用student_1student_2分别指向,两个不同Student对象。但两个Student对象的teacher成员变量的引用,指向两个不同Teacher对象。修改student_1对象的teacher成员变量,不会影响student_2对象的teacher成员变量,所以说是深拷贝
原型模式 - 图4

Ⅱ、通过对象序列化、反序列化实现深拷贝