原型模式及深浅拷贝问题探究

1.原型模式

需求描述:
克隆羊问题,现在有一只羊tom,1岁,白色。请编写程序创建和tom属性完全相同的10只羊。

思路分析:
如果使用最普通的方式,便是new出10羊的对象,将其属性均设置为tom一样。这种方法在创建新的对象时总需要重新获取原始对象的属性,效率低;而且总是需要重新初始化对象,不能动态获取对象运行时状态,不够灵活。
为了优化,我们采用原型模式(prototype)

原型模式基本介绍:原型模式是指用原型实例指定创建对象的种类,并通过拷贝原型来创建新的对象,而无需知道如何创建的细节。

工作原理: Object类是java中所有类的根类,Object类中提供了一个clone()方法,该方法可以将一个java对象复制一份,但是需要实现clone方法的类实现一个接口Cloneable。

package prototype.improve;

/**
 * @Author Worm
 * @Date 2020/8/10 19:31
 * @Version 1.0
 **/
public class Sheep implements Cloneable {
    private String name;
    private int age;
    private String color;

    public Sheep(String name, int age, String color) {
        this.name = name;
        this.age = age;
        this.color = color;
    }

    public Sheep() {
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }

    @Override
    protected Object clone() {
        Sheep sheep = null;
        try {
            sheep = (Sheep) super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return sheep;
    }

    @Override
    public String toString() {
        return "Sheep{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", color='" + color + '\'' +
                '}';

    }
}

客户端:可以看到创建出的对象是全新的对象,不是同一对象的引用。

package prototype.improve;


/**
 * @Author Worm
 * @Date 2020/8/10 19:40
 * @Version 1.0
 **/
public class Client {
    public static void main(String[] args) {
        System.out.println("原型模式完成对象的创建");
        Sheep sheep = new Sheep("tom", 1, "白色");
        Sheep sheep1 = (Sheep) sheep.clone();
        Sheep sheep2 = (Sheep) sheep.clone();
        Sheep sheep3 = (Sheep) sheep.clone();
        System.out.println("sheep1"+sheep1);
        System.out.println("sheep2"+sheep2);
        System.out.println("sheep3"+sheep3);
        System.out.println(sheep1==sheep2);/*false*/
    }
}

2.原型模式在Spring框架源码中的应用

在这里插入图片描述
在这里插入图片描述

进入getBean方法后继续往下走:

在这里插入图片描述

进入doGetBean方法:

在这里插入图片描述

核心方法在createBean中:
在这里插入图片描述

3.原型模式总结

在创建新对象比较复杂时,原型模式可以简化对象的创建过程,不用重新初始化对象,而是动态获取对象运行时状态,能够提高效率。
如果原始对象发生变化(增减属性),克隆对象会相应变化,不用修改代码。

4.浅拷贝与深拷贝

浅拷贝:对于基本数据类型的成员变量,浅拷贝直接进行值传递。对于引用数据类型的成员变量,会将引用值(地址)传递给新的对象,本质还是值传递,因此两个对象的该成员变量会指向同一个实例,这种情况下修改该成员变量会影响到另一个对象的该成员变量值,浅拷贝使用浅拷贝是使用默认的 clone()方法来实现。

现在为sheep添加一个friend属性,类型同样为sheep。

可以看到,浅拷贝导致两个对象的属性friend指向了同一个实例。

package prototype.improve;


/**
 * @Author Worm
 * @Date 2020/8/10 19:40
 * @Version 1.0
 **/
public class Client {
    public static void main(String[] args) {
        System.out.println("原型模式完成对象的创建");
        Sheep sheep = new Sheep("tom", 1, "白色");
        sheep.friend = new Sheep("jack", 2, "黑色");
        Sheep sheep1 = (Sheep) sheep.clone();

        Sheep sheep2 = (Sheep) sheep.clone();
        Sheep sheep3 = (Sheep) sheep.clone();
        System.out.println("sheep1" + sheep1);
        System.out.println("sheep2" + sheep2);
        System.out.println("sheep3" + sheep3);
        System.out.println(sheep1 == sheep2);/*false*/
//浅拷贝导致两个对象的属性friend指向了同一个实例。
        System.out.println(sheep2.friend.hashCode() == sheep.friend.hashCode());/*true*/

    }
}

深拷贝: 除了像浅拷贝那样复制所有基本数据类型的成员变量属性值,还会为所有引用数据类型变量申请存储空间并复制,直到该对象可达的所有对象。
深拷贝有两种常见的实现方式,第一种是修改浅拷贝的clone方法。第二种是通过对象序列化来实现深拷贝(推荐)

类型DeepProtoType持有一个DeepCloneableTarget类型的成员变量。

package prototype.deepclone;

import java.io.*;

/**
 * @Author Worm
 * @Date 2020/8/11 14:50
 * @Version 1.0
 **/
public class DeepProtoType implements Cloneable,Serializable {
    public String name;
    public DeepCloneableTarget deepCloneableTarget;


//    深拷贝,方式一,使用修改后的clone方法

    @Override
    protected Object clone() throws CloneNotSupportedException {
        Object deep = null;
        deep = super.clone();
        DeepProtoType deepProtoType = (DeepProtoType) deep;
        deepProtoType.deepCloneableTarget = (DeepCloneableTarget) deepCloneableTarget.clone();
        return deepProtoType;
    }


    //    深拷贝,方式2 通过对象的序列化实现(推荐)
    public Object deepClone() {
        ByteArrayOutputStream byteArrayOutputStream = null;
        ObjectOutputStream objectOutputStream = null;
        ByteArrayInputStream byteArrayInputStream = null;
        ObjectInputStream objectInputStream = null;
        try {
//            序列化
            byteArrayOutputStream = new ByteArrayOutputStream();
            objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
            objectOutputStream.writeObject(this);/*将当前对象以对象流的方式输出*/
//反序列化
            byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
            objectInputStream = new ObjectInputStream(byteArrayInputStream);
            DeepProtoType deepProtoType = (DeepProtoType) objectInputStream.readObject();
            return deepProtoType;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        } finally {
            try {
                byteArrayOutputStream.close();
                objectOutputStream.close();
                byteArrayInputStream.close();
                objectInputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }


        }

    }

}
package prototype.deepclone;

import java.io.Serializable;

/**
 * @Author Worm
 * @Date 2020/8/11 14:49
 * @Version 1.0
 **/
public class DeepCloneableTarget implements Serializable, Cloneable {

    /**
     *
     */
    private static final long serialVersionUID = 1L;

    private String cloneName;

    private String cloneClass;

    //构造器
    public DeepCloneableTarget(String cloneName, String cloneClass) {
        this.cloneName = cloneName;
        this.cloneClass = cloneClass;
    }

    //因为该类的属性,都是String , 因此我们这里使用默认的clone完成即可
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

客户端,检查两种深拷贝方式:

package prototype.deepclone;

/**
 * @Author Worm
 * @Date 2020/8/11 15:01
 * @Version 1.0
 **/
public class Client {
    public static void main(String[] args) throws CloneNotSupportedException {
        DeepProtoType deepProtoType = new DeepProtoType();
        deepProtoType.name = "tom";
        deepProtoType.deepCloneableTarget = new DeepCloneableTarget("cc", "cc class");
//        方式1完成深拷贝
//        DeepProtoType clone = (DeepProtoType) deepProtoType.clone();
//        方式2深拷贝
        DeepProtoType clone = (DeepProtoType) deepProtoType.deepClone();
        System.out.println(deepProtoType.name + "  " + deepProtoType.deepCloneableTarget.hashCode());/*tom  20671747*/
        System.out.println(clone.name + "  " + clone.deepCloneableTarget.hashCode());/*tom  1854778591*/
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值