浅克隆与深度克隆

来源:互联网 发布:qq空间钓鱼网站源码 编辑:程序博客网 时间:2024/05/12 19:00

1、为什么要克隆

   我们在编写程序的时候,常常需要进行对象的拷贝(例如:把student1拷贝给student2),拷贝的对象要求是独立的,与母本没联系。而一般的赋值操作符只是把对象的引用复制过去,两者指向同一块内存,这样的话当改变student1的属性时,student2也会改变,这不是我们想要的结果。这时候就需要进行克隆。

2、克隆分类

    1)浅克隆:进行浅克隆时,开辟一块新的内存把student1对象所占的内存块原封不动的拷贝过去给student2。

如图:

shallowclone.png

    2)深度克隆:注意到上面的图,对于基本类型的变量name、age,浅克隆把它们的值从student1拷贝给student2得到两份一样的值。而对于引用类型courseGrade,拷贝的只是courseGrade的一个引用,这两个引用指向同一个courseGrade对象。这又跟之前的直接赋值操作类似了,改变student1的courseGrade属性,student2也会跟着改变。因此,浅克隆适合对于全部是基本类型的对象。对于有对象的嵌套的对象要用深克隆。通过深克隆,两对象student1、student2指向的courseGrade对象是不同的。

如图:

deepclone.png

3.克隆的实现

    1)浅克隆的实现:浅克隆的实现比较简单,我们首先要实现Cloneable接口,它是一个标记接口,没用任何方法。实现Cloneable接口的类标记为可克隆的,而且它的对象可以使用在Object类中定义的clone()方法克隆,Object类定义的克隆方法是属于浅克隆的。因为Object类是任何其他类的父类,所以,我们只需要super.clone()就可以进行浅克隆了。再者,我们定义的类是要给其他类用的,所以,一般我们会覆盖clone()方法。代码如下:

public class Student implements Cloneable{    private String name;    private int yearOld;    private CourseGrade courseGrade;      /*******************/    @Override    public Object clone() throws CloneNotSupportedException{        Student student=null;        student=(Student)super.clone();        return student;    }}

      2)深克隆的实现:深度克隆的实现主要有两种方法。

       1>先来个super.clone()把基本类型给浅克隆过去,然后再对引用类型的对象克隆后赋值给克隆体的这个属性,如果这个引用类型的对象下面还有引用类型,也进行同样的操作,即克隆到底!因此,可以看出,这种深度克隆的方法只适合于层次少的类。代码如下:

public class Student implements Cloneable{    private String name;    private int yearOld;    private CourseGrade courseGrade;    /*******************/    @Override    public Object clone() throws CloneNotSupportedException{        Student student=null;        student=(Student)super.clone();        student.courseGrade=(CourseGrade)this.courseGrade.clone();              return student;    }}public class CourseGrade implements Cloneable{    private int chineseGrade;    private int mathGrade;    private int EnglishGrade;    /*******************/    @Override    public Object clone() throws CloneNotSupportedException{               return super.clone();       }}

            2>利用序列化和反序列化来实现,这种克隆方式不管你的类层次有多深,都能一步搞定。唯一的要求是克隆的类及下面层的类都要实现Serializable接口,这个接口同样没有提供任何方法,是标记接口,实现这个接口的类才可被序列化。代码如下:

public class Student implements Serializable{    private String name;    private int yearOld;    private CourseGrade courseGrade;    /*******************/    @Override    public Object clone() throws CloneNotSupportedException{           Student student=null;            try {            ByteArrayOutputStream bu=new ByteArrayOutputStream();            ObjectOutputStream ou=new ObjectOutputStream(bu);            ou.writeObject(this);            ByteArrayInputStream bi=new ByteArrayInputStream(bu.toByteArray());            ObjectInputStream oi=new ObjectInputStream(bi);            student=(Student)oi.readObject();        } catch (IOException ex) {            //Logger.getLogger(Student.class.getName()).log(Level.SEVERE, null, ex);        } catch (ClassNotFoundException ex) {            //Logger.getLogger(Student.class.getName()).log(Level.SEVERE, null, ex);        }        return student;    }}public class CourseGrade implements Serializable{    private int chineseGrade;    private int mathGrade;    private int EnglishGrade;    /*******************/}

4、克隆后的结果

   主类代码如下:

public class Test1 {    /**     * @param args the command line arguments     */    public static void main(String[] args) throws CloneNotSupportedException {        // TODO code application logic here        CourseGrade courseGrade=new CourseGrade(100,100,100);        Student student1=new Student("小明",20,courseGrade);        System.out.println("克隆前student1属性");        System.out.println("姓名:"+student1.getName()+"||年龄:"+student1.getYearOld()+"||语文成绩:"+student1.getCourseGrade().getChineseGrade());        Student student2=(Student)student1.clone();        student2.setName("小红");        student2.setYearOld(15);        student2.getCourseGrade().setChineseGrade(90);        System.out.println("克隆后修改student2属性,student1和student2的变化");        System.out.println("姓名:"+student1.getName()+"||年龄:"+student1.getYearOld()+"||语文成绩:"+student1.getCourseGrade().getChineseGrade());        System.out.println("姓名:"+student2.getName()+"||年龄:"+student2.getYearOld()+"||语文成绩:"+student2.getCourseGrade().getChineseGrade());           }    }

  1)浅克隆结果:

克隆前student1属性姓名:小明||年龄:20||语文成绩:100克隆后修改student2属性,student1和student2的变化姓名:小明||年龄:20||语文成绩:90姓名:小红||年龄:15||语文成绩:90

   2)深度克隆结果:

克隆前student1属性姓名:小明||年龄:20||语文成绩:100克隆后修改student2属性,student1和student2的变化姓名:小明||年龄:20||语文成绩:100姓名:小红||年龄:15||语文成绩:90

0 0