一、描述:
将一个对象作为原型,通过对其进行复制而克隆出多个和原型类似的新实例。
二、特点:
用一个已经创建的实例作为原型,通过复制该原型对象来创建一个和原型相同或相似的新对象。原型实例指定了要创建的对象的种类。用这种方式创建对象非常高效,根本无须知道对象创建的细节。
三、优点:
(1)Java自带的原型模式基于内存二进制流的复制,在性能上比直接new一个对象更加优秀。
(2)可以使用深克隆方式保存对象的状态,使用原型模式将对象复制一份,并将其状态保存起来,简化了创建对象的过程,以便在需要的时候使用(例如恢复到历史某一状态),可辅助实现撤销操作。
四、应用:
Object的clone方法,实体类实现Cloneable接口类,重写clone()方法,clone方法有浅拷贝和深拷贝两种:
(1)浅拷贝:只拷贝当前主类的对象,建立一个新的复制对象,但是新的复制对象中的子对象依旧引用之前的主类的子对象地址。(注意:测试clone方法的结果,不能用@Data注解,因为@Data注解重写了hashCode方法,相同属性相同值的情况下,hashCode值一致。)
- public class User implements Cloneable {
- private String name;
- private String sex;
- private Integer age;
- private School school;
-
- public String getName() {
- return name;
- }
-
- public void setName(String name) {
- this.name = name;
- }
-
- public String getSex() {
- return sex;
- }
-
- public void setSex(String sex) {
- this.sex = sex;
- }
-
- public Integer getAge() {
- return age;
- }
-
- public void setAge(Integer age) {
- this.age = age;
- }
-
- public School getSchool() {
- return school;
- }
-
- public void setSchool(School school) {
- this.school = school;
- }
-
- @Override
- protected User clone() throws CloneNotSupportedException {
- return (User) super.clone();
- }
-
- public static class School implements Cloneable {
- private String name;
-
- public String getName() {
- return name;
- }
-
- public void setName(String name) {
- this.name = name;
- }
-
- @Override
- protected Object clone() throws CloneNotSupportedException {
- return super.clone();
- }
- }
- }
测试:
- @Slf4j
- public class MainTest {
- public static void main(String[] args) throws CloneNotSupportedException {
- User user = new User();
- user.setName("张三");
- user.setAge(18);
- User.School school = new User.School();
- school.setName("华师小学");
- user.setSchool(school);
-
- User user2 = user.clone();
- log.info("user:{}",JSON.toJSONString(user));
- log.info("user2:{}",JSON.toJSONString(user2));
- log.info("user-hashCode:{},user2-hashCode:{},isEquals:{}", user.hashCode(), user2.hashCode(), user.hashCode() == user2.hashCode());
- log.info("user-school-hashCode:{},user2-school-hashCode:{}, isEquals:{}", user.getSchool().hashCode(), user2.getSchool().hashCode(), user.getSchool().hashCode() == user2.getSchool().hashCode());
- }
- }
运行结果:
user:{"age":18,"name":"张三","school":{"name":"华师小学"}}
user2:{"age":18,"name":"张三","school":{"name":"华师小学"}}
user-hashCode:662736689,user2-hashCode:1320677379,isEquals:false
user-school-hashCode:852687460,user2-school-hashCode:852687460, isEquals:true
从结果可以看出来,主对象在克隆之后,hashCode值变化,说明为克隆主对象又重新开辟了内存存储。但是克隆子对象school的hashCode值仍然为原来的hashCode,说明克隆后的user2对象中的school仍然引用的user的school对象地址。这就是浅拷贝。
浅拷贝的util方法有:
- BeanUtil.copyProperties(user, user2);
(2)深拷贝:比浅拷贝更进一步,子对象也都重新开辟了新的内存存储,重写clone方法:
- /**
- * User
- *
- * @author zhouxy
- * @date 2022/5/24
- **/
- public class User implements Cloneable {
- private String name;
- private String sex;
- private Integer age;
- private School school;
-
- //getter、setter方法
- ......
-
- @Override
- protected User clone() throws CloneNotSupportedException {
- User copyUser = (User) super.clone();
- //重写school的clone方法
- School school = copyUser.getSchool().clone();
- copyUser.setSchool(school);
- return copyUser;
- }
-
- public static class School implements Cloneable {
- private String name;
-
- //getter、setter方法
- .....
-
- @Override
- protected School clone() throws CloneNotSupportedException {
- return (School) super.clone();
- }
- }
- }
测试代码仍然和浅拷贝的测试代码一致,直接显示测试结果:
- user:{"age":18,"name":"张三","school":{"name":"华师小学"}}
- user2:{"age":18,"name":"张三","school":{"name":"华师小学"}}
- user-hashCode:662736689,user2-hashCode:1320677379,isEquals:false
- user-school-hashCode:852687460,user2-school-hashCode:246399377, isEquals:false
school的对象的hashCode也发生了变化。