Java 设计模式(一)原型模式 ProtoType Model

一、Java 的原型模式是什么?

当我们拥有一个对象 obj_01 的时候,我们想通过拷贝这个对象来得到另一个对象 obj_02,类似于复制粘贴功能。这个过程叫做【克隆】,这个模型就叫做原型模式。

 

二、原型模式分为两种:浅克隆深克隆

代码说明:ProtoType01.java 为待克隆的 Java Bean,Student.java 为ProtoType01 的一个引用类型的成员变量,ProtoType01Test 为测试用例。

1、浅克隆。java 中每个对象都是 Object.java 的子类,Object 有一个方法 clone(),所以每个类都可以通过 super.clone()方法来实现浅克隆。浅克隆会给新对象一个新的内存地址,但是新对象引用类型的成员变量的地址仍然不会改变。待克隆的类必须实现接口 Cloneable,否则会抛出异常。参见 ProtoType01.java 的 clone()方法。

 

在 ProtoType01Test.java 中我们通过调用 test01来克隆,并将内存地址打印出来。(我们通过System.identityHashCode() 方法来获取对象的内存地址,即使重写了 hasCode()方法,该值也不会改变。)

打印结果为:

427451634
846813423
1019071692
1019071692
mmm
mmm
 

通过观察打印结果我们可以发现,克隆前后的内存地址发生了改变(从 427451634 变为了 846813423),但是其引用类型的成员变量内存地址并没有发生任何变化(一直都是 1019071692 ),并且我们在浅克隆之后给 Student 的 name 设置了值,它覆盖了原对象的name值,变成了 mmm。

 

2、深克隆。深克隆是相较浅克隆而言的,它不仅会改变克隆后新对象的内存地址,它还会给新对象的每一个成员变量重新分配内存地址(即使该成员变量为引用类型)。也就是说新对象和老对象在内存的占用上已经完全不同了,没有任何共用的地方。

我们通过流的转化实现深克隆,实现流的转化就必须将对象序列化,所以待克隆的类以及它属性中的对象都必须实现 Serializable 接口,当我们将一个对象转化成流的时候,JVM 会保留原有对象,并重新 "复制" 一个对象,所以我们通过将一个对象转化成对象流,再将该对象流转化回对象来实现深克隆。参见 ProtoType01.java 的 deepClone()方法。

 

在 ProtoType01Test.java 中我们通过调用 test02来深克隆,并将内存地址打印出来。打印结果为:

9964338
373773844
2114387947
627328633
nnn
mmm

通过观察打印结果我们可以发现,无论是新的克隆后的新对象,还是它的引用类型 Student 的内存地址都发生了改变,所以,原对象 的 student().getName() 值依然为 nnn,没有改变。

public class Student implements Serializable{

    private static final long serializableVersionId = 1L;
    private  String name; 
    
    public  void setName(String name) {
            this.name  = name;
    }
    public  String getName(){
            return  this.name;
    }
}
public class ProtoType01 implements Cloneable, Serializable{
    
    private static final long serializableVersionId = 1L;
    private String attr;
    private Student student;

    //浅克隆
    public ProtoType01 clone() {
        Object obj = null;
        try {
            obj = super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return (ProtoType01)obj;
    } 
    
    //深克隆
    public ProtoType01 deepClone() {
        try {
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            ObjectOutputStream objectOut = new ObjectOutputStream(out);
            objectOut.writeObject(this);
            
            ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
            ObjectInputStream objectIn = new ObjectInputStream(in);
            return (ProtoType01)objectIn.readObject();
            
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        }
        return null;
      }
    public String getAttr() {
        return attr;
    }
    public void setAttr(String attr) {
        this.attr = attr;
    }
    public Student getStudent() {
        return student;
    }
    public void setStudent(Student student) {
        this.student = student;
    }
}

public class ProtoType01Test {

    @Test
    public void test01() {
        ProtoType01 pt01 = new ProtoType01();
        Student student = new Student();
        student.setName("nnn");
        pt01.setStudent(student);
        
        ProtoType01 pt02 = pt01.clone();
        
        pt02.getStudent().setName("mmm");
        
        //打印克隆对象的内存地址
        System.out.println(System.identityHashCode(pt01));
        System.out.println(System.identityHashCode(pt02));
        
        //打印克隆对象引用对象类型Student的内存地址
        System.out.println(System.identityHashCode(pt01.getStudent()));
        System.out.println(System.identityHashCode(pt02.getStudent()));
        
        System.out.println((pt01.getStudent().getName()));
        System.out.println((pt02.getStudent().getName()));
    }
    
    @Test
    public void test02() {
        ProtoType01 pt01 = new ProtoType01();
        Student student = new Student();
        student.setName("nnn");
        pt01.setStudent(student);
        
        ProtoType01 pt02 = pt01.deepClone();
        
        pt02.getStudent().setName("mmm");
        
        //打印克隆对象的内存地址
        System.out.println(System.identityHashCode(pt01));
        System.out.println(System.identityHashCode(pt02));
        
        //打印克隆对象引用对象类型Student的内存地址
        System.out.println(System.identityHashCode(pt01.getStudent()));
        System.out.println(System.identityHashCode(pt02.getStudent()));
        
        System.out.println((pt01.getStudent().getName()));
        System.out.println((pt02.getStudent().getName()));
    }
}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值