Java常用设计模式————原型模式(二)之深拷贝与浅拷贝

引言

clone顾名思义就是复制, 在Java语言中, clone方法被对象调用,所以会复制对象。所谓的复制对象,首先要分配一个和源对象同样大小的空间,在这个空间中创建一个新的对象。那么在java语言中,有几种方式可以创建对象呢? 

1 使用new操作符创建一个对象 

2 使用clone方法复制一个对象 

那么这两种方式有什么相同和不同呢? new操作符的本意是分配内存。程序执行到new操作符时, 首先去看new操作符后面的类型,因为知道了类型,才能知道要分配多大的内存空间。分配完内存之后,再调用构造函数,填充对象的各个域,这一步叫做对象的初始化,构造方法返回后,一个对象创建完毕,可以把他的引用(地址)发布到外部,在外部就可以使用这个引用操纵这个对象。而clone在第一步是和new相似的, 都是分配内存,调用clone方法时,分配的内存和源对象(即调用clone方法的对象)相同,然后再使用原对象中对应的各个域,填充新对象的域, 填充完成之后,clone方法返回,一个新的相同的对象被创建,同样可以把这个新对象的引用发布到外部。【详解Java中的clone方法

拷贝的种类

引用拷贝

package design.pattern.copy;
/**
 * 引用拷贝
 * <br>类名:CiteCopy<br>
 * 作者: mht<br>
 * 日期: 2018年4月1日-下午6:13:37<br>
 */
public class CiteCopy {

    public static void main(String[] args) {
        Student s1 = new Student();
        Student s2 = s1;
        System.out.println(s1 + "\n" + s2);
    }
}

结果:

design.pattern.copy.Student@6d06d12f
design.pattern.copy.Student@6d06d12f


 

对象拷贝

 

package design.pattern.copy;
/**
 * 对象拷贝
 * <br>类名:Copy<br>
 * 作者: mht<br>
 * 日期: 2018年4月1日-下午6:13:37<br>
 */
public class Copy {

    public static void main(String[] args) {
        Student s1 = new Student();
        Student s2 = (Student) s1.clone();
        System.out.println(s1 + "\n" + s2);
    }
}

结果:

design.pattern.copy.Student@15db9742
design.pattern.copy.Student@6d06d69c

浅拷贝

package design.pattern.copy;
/**
 * 浅拷贝
 * <br>类名:Copy<br>
 * 作者: mht<br>
 * 日期: 2018年4月1日-下午6:13:37<br>
 */
public class Copy {

    public static void main(String[] args) {
        Student s1 = new Student();
        Teacher t1 = new Teacher();
        s1.setTeacher(t1);
        System.out.println("t1的内存地址:" + t1);
        Student s2 = (Student) s1.clone();
        // 两个学生对象的内存为:
        System.out.println(s1 + "\n" + s2);
        // 两个学生对象中的老师对象为:
        System.out.println(s1.getTeacher() + "\n" +  s2.getTeacher());
    }
}

结果:

t1的内存地址:design.pattern.copy.Teacher@15db9742
design.pattern.copy.Student@6d06d69c
design.pattern.copy.Student@7852e922
design.pattern.copy.Teacher@15db9742
design.pattern.copy.Teacher@15db9742

 

深拷贝

 

        通过clone方式实现的拷贝,默认是采用浅拷贝的方式,即只拷贝调用clone方法的对象,而对象内部引用的成员变量对象则不会一同进行复制,因此,就算是将内部的对象再进行clone拷贝,依然会出现内部对象的内部引用对象没有复制的问题。所以一般情况下,clone可以实现不彻底的深拷贝,无法实现彻底的深拷贝。

        通过Serializable实现深拷贝,会真正的实现整个对象的复制。

package design.pattern.copy;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

public class Student implements Serializable{
    private String name;
    private int age;
    private Teacher teacher;
    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 Teacher getTeacher() {
        return teacher;
    }
    public void setTeacher(Teacher teacher) {
        this.teacher = teacher;
    }
    
    /**
     * 深拷贝
     * <br>作者: mht<br> 
     * 时间:2018年4月1日-下午10:53:41<br>
     * @return
     */
    protected Object deepClone(){
        try {
            // 序列化
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(bos);
            oos.writeObject(this);
            // 反序列化
            ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
            ObjectInputStream ois = new ObjectInputStream(bis);
            
            return ois.readObject();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        
        return null;
    }
}
package design.pattern.copy;

import java.io.Serializable;

public class Teacher implements Serializable{
    private String name;
    private int age;
    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;
    }
}
package design.pattern.copy;
/**
 * Serializable序列化深拷贝
 * <br>类名:Copy<br>
 * 作者: mht<br>
 * 日期: 2018年4月1日-下午6:13:37<br>
 */
public class Copy {

    public static void main(String[] args) {
        Student s1 = new Student();
        Teacher t1 = new Teacher();
        s1.setTeacher(t1);
        System.out.println("t1的内存地址:" + t1);
        System.out.println("==========================");
        Student s2 = (Student) s1.deepClone();
        // 两个学生对象的内存为:
        System.out.println(s1 + "\n" + s2);
        System.out.println("==========================");
        // 两个学生对象中的老师对象为:
        System.out.println("s1.getTeacher() : " + s1.getTeacher() + "\ns2.getTeacher() : " +  s2.getTeacher());
    }
}

结果:

t1的内存地址:design.pattern.copy.Teacher@15db9742
==========================
design.pattern.copy.Student@3d4eac69
design.pattern.copy.Student@232204a1
==========================
s1.getTeacher() : design.pattern.copy.Teacher@15db9742
s2.getTeacher() : design.pattern.copy.Teacher@4aa298b7

从上述结果可以看出,不仅student对象进行了复制,其s1内部的teacher对象也一同被复制了一个新的对象出来。但是要注意的是,Teacher类也一定要实现Serializable接口才可以,否则会产生NotSerializableException的运行时异常。

 

相关推荐
©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页