Bootstrap

原型模式(克隆模式)

  1. 原型模式简介:也叫克隆模式
	原型模式使用原型实例指定创建对象的种类,并且通过拷贝原型对象创建新的对象。
   	Prototype模式提供了一个通过已存在对象进行新对象创建的接口(clone), clone()实现和具体的语言
 相关,在C++中通过拷贝构造函数实现。
 	原型模式实际上就是从一个对象再创建另外一个可定制的对象,而且不需要知道任何创建的细节。
 在初始化的信息不发生变化的情况下,克隆是最好的办法,既隐藏了对象创建的细节,又大大提高了性能。
 因为如果不用clone,每次new都需要执行一次构造函数,如果构造函数的执行时间很长,那么多次的执行
 初始化操作就太低效了。
	原型模式实现clone接口的时候必须使用深拷贝。
	原型模式重点在从自身赋值自己创建新的类对象,隐藏创建的细节。

2. 什么叫浅克隆和深克隆
在这里插入图片描述
浅克隆:Address并没有被克隆而是克隆的引用
深克隆:Address对象也被克隆

3. 为什么要克隆?
大家先思考一个问题,为什么需要克隆对象?直接new一个对象不行吗?
答案是:克隆的对象可能包含一些已经修改过的属性,而new出来的对象的属性都还是初始化时候的值,所以当需要一个新的对象来保存当前对象的“状态”就靠clone方法了。那么我把这个对象的临时属性一个一个的赋值给我新new的对象不也行嘛?可以是可以,但是一来麻烦不说,二来,大家通过上面的源码都发现了clone是一个native方法,就是快啊,在底层实现的。
  提个醒,我们常见的Object a=new Object();Object b;b=a;这种形式的代码复制的是引用,即对象在内存中的地址,a和b对象仍然指向了同一个对象。
  而通过clone方法赋值的对象跟原来的对象时同时独立存在的。

4. 浅克隆

/**
 * @author: 张瑛
 * @date: 2019/10/29-14:43
 */
public class TestClone1 {

    public static void main(String [] args){
        Student stu1 = new Student();
        stu1.setNumber(12345);
        Student stu2 = (Student)stu1.clone();

        System.out.println("学生1:" + stu1.getNumber());
        System.out.println("学生2:" + stu2.getNumber());

        stu2.setNumber(54321);

        System.out.println("学生1:" + stu1.getNumber());
        System.out.println("学生2:" + stu2.getNumber());
    }
}

class Student implements Cloneable{
    private int number;

    public int getNumber() {
        return number;
    }

    public void setNumber(int number) {
        this.number = number;
    }

    @Override
    public Object clone() {
        Student stu = null;
        try{
            stu = (Student)super.clone();
        }catch(CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return stu;
    }
}


5.深克隆
问题代码:

package com.tencent.clone;

/**
 * @author: 张瑛
 * @date: 2019/10/29-14:47
 */
public class TestClone2 {
    public static void main(String [] args){

        Address addr = new Address();
        addr.setAdd("杭州市");
        Student2 stu2 = new Student2();
        stu2.setNumber(123);
        stu2.setAddr(addr);

        Student2 stu3 = (Student2)stu2.clone();

        System.out.println("学生1:" + stu2.getNumber() + ",地址:" + stu2.getAddr().getAdd());
        System.out.println("学生2:" + stu3.getNumber() + ",地址:" + stu3.getAddr().getAdd());

        addr.setAdd("安庆市");

        System.out.println("学生1:" + stu2.getNumber() + ",地址:" + stu2.getAddr().getAdd());
        System.out.println("学生2:" + stu3.getNumber() + ",地址:" + stu3.getAddr().getAdd());

        //结果:
        /**
         * 学生1:123,地址:杭州市
         * 学生2:123,地址:杭州市
         * 学生1:123,地址:安庆市
         * 学生2:123,地址:安庆市
         * 就是说:addr.setAdd("安庆市")后,Address并没有被克隆而是克隆的引用
         */
    }
}

class Address {
    private String add;

    public String getAdd() {
        return add;
    }

    public void setAdd(String add) {
        this.add = add;
    }
}

class Student2 implements Cloneable{
    private int number;

    private Address addr;

    public Address getAddr() {
        return addr;
    }

    public void setAddr(Address addr) {
        this.addr = addr;
    }

    public int getNumber() {
        return number;
    }

    public void setNumber(int number) {
        this.number = number;
    }

    @Override
    public Object clone() {
        Student2 stu = null;
        try{
            stu = (Student2)super.clone();
        }catch(CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return stu;
    }
}



解决:

package com.tencent.clone;

/**
 * @author: 张瑛
 * @date: 2019/10/29-14:47
 * Address类也实现 Cloneable接口
 * 修改clone方法
 */
public class TestClone2 {
    public static void main(String [] args){

        Address addr = new Address();
        addr.setAdd("杭州市");
        Student2 stu2 = new Student2();
        stu2.setNumber(123);
        stu2.setAddr(addr);

        Student2 stu3 = (Student2)stu2.clone();

        System.out.println("学生1:" + stu2.getNumber() + ",地址:" + stu2.getAddr().getAdd());
        System.out.println("学生2:" + stu3.getNumber() + ",地址:" + stu3.getAddr().getAdd());

        addr.setAdd("安庆市");

        System.out.println("学生1:" + stu2.getNumber() + ",地址:" + stu2.getAddr().getAdd());
        System.out.println("学生2:" + stu3.getNumber() + ",地址:" + stu3.getAddr().getAdd());

        //结果:
        /**
         * 学生1:123,地址:杭州市
         * 学生2:123,地址:杭州市
         * 学生1:123,地址:安庆市
         * 学生2:123,地址:杭州市
         */
    }
}

class Address implements Cloneable{
    private String add;

    public String getAdd() {
        return add;
    }

    public void setAdd(String add) {
        this.add = add;
    }

    @Override
    public Object clone() {
        Address addr = null;
        try{
            addr = (Address)super.clone();
        }catch(CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return addr;
    }
}

class Student2 implements Cloneable{
    private int number;

    private Address addr;

    public Address getAddr() {
        return addr;
    }

    public void setAddr(Address addr) {
        this.addr = addr;
    }

    public int getNumber() {
        return number;
    }

    public void setNumber(int number) {
        this.number = number;
    }

    @Override
    public Object clone() {
        Student2 stu = null;
        try{
            stu = (Student2)super.clone();   //浅复制
            stu.addr = (Address)addr.clone();   //深度复制
        }catch(CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return stu;
    }
}



;