浅克隆与深度克隆

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

 
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值