1. 原型模式
- 对原型进行拷贝来创建新对象
- 原型模式的两种实现方法
- 浅拷贝
- 深拷贝
1.2 核心组成
- IPrototype
- ConcretePrototype
- Client
1.3 应用场景
- 创建新对象成本较大,新的对象可以通过原型模式对已有对象进行复制来获得
1.4 浅拷贝与深拷贝区别
- 浅拷贝得到的对象跟原始对象共享数据,而深拷贝会复制数据本身
- 浅拷贝只会复制对象中基本数据类型数据和引用对象的内存地址,不会递归地复制引用对象,以及引用对象的引用对象……而深拷贝得到的是一份完完全全独立的对象
2. 浅拷贝
- 实现 Cloneable 接口
- 重写 clone()
- 基本数据类型可以达到完全复制,引用数据类型不可以,因为引用数据类型仅仅是拷贝了一份引用
public void demo() {
ArrayList<String> list = new ArrayList<>();
list.add("AAA");
list.add("BBB");
Object copyList = list.clone();
System.out.println(copyList == list);
System.out.println(copyList);
// 结果是false, 但内容是一样的
}
2.2 对象复制
@Test
public void test() {
Course course = new Course("English");
Student student = new Student("Tinyspot", 20, course);
Student stu2 = new Student();
stu2.setName(student.getName());
stu2.setAge(student.getAge());
stu2.setCourse(student.getCourse());
student.setName("222");
student.setAge(22);
student.getCourse().setTitle("Chinese");
// or course.setTitle("Chinese");
System.out.println(student.getCourse() == stu2.getCourse()); // true
}
打印对象:
student: Student(name=222, age=22, course=Course(title=Chinese))
stu2: Student(name=Tinyspot, age=20, course=Course(title=Chinese))
2.3 浅拷贝示例
- 浅拷贝的引用类型会随原型对象(拷贝对象)改变而改变
- 实现 Cloneable 接口
@Test
public void test() throws CloneNotSupportedException {
Student student = new Student("Tinyspot", 20, new Course("English"));
Student stuCopy = student.clone();
student.setAge(22);
stuCopy.getCourse().setTitle("Chinese");
}
打印对象:
student: Student(name=Tinyspot, age=22, course=Course(title=Chinese))
stuCopy: Student(name=Tinyspot, age=20, course=Course(title=Chinese))
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Student implements Cloneable {
private String name;
private Integer age;
private Course course;
@Override
public Student clone() throws CloneNotSupportedException {
return (Student) super.clone();
}
}
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Course {
private String title;
}
3. 深拷贝
- 递归拷贝对象、对象的引用对象以及引用对象的引用对象……直到要拷贝的对象只包含基本数据类型数据,没有引用对象为止
3.1 实现方式一
- 引用类型也实现
Cloneable
, 重写clone()
- 当对象之间存在多重嵌套引用,每一层对象对应的类都必须支持深克隆
@Test
public void test() throws CloneNotSupportedException {
Student student = new Student("Tinyspot", 20, new Course("English"));
Student stuCopy = student.clone();
student.setAge(22);
student.getCourse().setTitle("Chinese");
}
打印对象:
student: Student(name=Tinyspot, age=22, course=Course(title=Chinese))
stuCopy: Student(name=Tinyspot, age=20, course=Course(title=English))
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Student implements Cloneable {
private String name;
private Integer age;
private Course course;
@Override
public Student clone() throws CloneNotSupportedException {
Student student = (Student) super.clone();
// 将拷贝出的对象赋给成员变量
// or student.course = this.course.clone();
student.setCourse(this.course.clone());
return student;
}
}
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Course implements Cloneable {
private String title;
@Override
public Course clone() throws CloneNotSupportedException {
return (Course) super.clone();
}
}
3.2 实现方式二
- 先将对象序列化,然后再反序列化成新的对象
- Serializable 读取二进制流
@Test
public void test() throws CloneNotSupportedException {
Person person = new Person();
person.setName("Tinyspot");
person.getList().add("AAA");
// 测试浅拷贝
Person personCopy = person.clone();
person.setName("222");
person.getList().add("BBB");
// or personCopy.getList().add("BBB");
System.out.println("person: " + person);
System.out.println("personCopy: " + personCopy);
System.out.println(person.getList() == personCopy.getList()); // true
}
打印对象:
person: Person(name=222, age=null, list=[AAA, BBB])
personCopy: Person(name=Tinyspot, age=null, list=[AAA, BBB])
@Test
public void test() {
Person person = new Person();
person.setName("Tinyspot");
person.getList().add("AAA");
// 测试深拷贝
Person personCopy = person.deepClone();
personCopy.getList().add("BBB");
}
打印对象
person: Person(name=Tinyspot, age=null, list=[AAA])
personCopy: Person(name=Tinyspot, age=null, list=[AAA, BBB])
网友评论