java中的Clone(深拷贝,浅拷贝)

时间:2021-11-14 19:50:25
 

随着现代科技的发展,人类已经能够克隆(clone)牛,羊等动物。Java是面向对象,也能够实现对象的克隆(clone),在之前的学习中见到引用的赋值操作,如下例所示:

 

 

首先定义一个Student类

 

public class Student implements Cloneable{

 

    private String studentName;

 

    private int age;

   

    public int getAge() {

       return age;

    }

 

    public void setAge(int age) {

       this.age = age;

    }

 

    public String getStudentName() {

       return studentName;

    }

 

    public void setStudentName(String studentName) {

       this.studentName = studentName;

    }

 

 

}

 

入口函数:

public static void main(String args[]){

      

       Student student0 = new Student();

      

       student0.setStudentName("xiaoming");

      

       Student student1 = student0;

      

       System.out.println("student0.getStudentName:"+student0.getStudentName());

      

       System.out.println("student1.getStudentName:"+student1.getStudentName());

 

运行结果:打印输出:

 

student0.getStudentName:xiaoming

student1.getStudentName:xiaoming

 

在入口函数中student0 被付给了student1两引用指向了内存中的同一块空间,所以通过student0对对象的操作与通过student1对对象的操作完全一致。

 

 

 

有时候需要创造一个student0的副本,内容与student0完全一致,但是以后可以根据需要对student1内容修改,而不会影响到student0,这时候我们就需要用到clone.

 

虽然Clone方法在Object中存在的,但是如果想要调用clone必须实现Cloneable接口,否则会抛出java.lang.CloneNotSupportedException。

看一下实例

 

public class Student implements Cloneable{

 

    private String studentName;

 

    private int age;

   

    public int getAge() {

       return age;

    }

 

    public void setAge(int age) {

       this.age = age;

    }

 

    public String getStudentName() {

       return studentName;

    }

 

    public void setStudentName(String studentName) {

       this.studentName = studentName;

    }

 

   

    protected Object clone() throws CloneNotSupportedException {

      

       Student student =  (Student) super.clone();

   

       return student;

      

      

    }

   

}

 

入口函数:

public static void main(String args[]){

      

       Student student = new Student();

       student.setAge(10);

       student.setStudentName("xiaobai");

      

          

       try {

           Student s1  = (Student) student.clone();

       System.out.println("student.studentName:"+student.getStudentName());

           System.out.println("student.age:"+student.getAge());

          

           System.out.println("s1.studentName:"+s1.getStudentName());

           System.out.println("s1.age:"+s1.getAge());

   

       } catch (CloneNotSupportedException e) {

                  e.printStackTrace();

       }

    }

 

打印运行输出结果:

 

student.studentName:xiaobai

student.age:10

s1.studentName:xiaobai

s1.age:10

 

我们可以看出,student 和s1的内容完全一致,而且我们可以修改s1的值,而不会影响student的值。

修改入口函数:

public static void main(String args[]){

      

      

       Student student = new Student();

       student.setAge(10);

       student.setStudentName("xiaobai");

      

      

       try {

           Student s1  = (Student) student.clone();

           s1.setStudentName("xiaohei");

           System.out.println("student.studentName:"+student.getStudentName());

           System.out.println("student.age:"+student.getAge());

          

           System.out.println("s1.studentName:"+s1.getStudentName());

           System.out.println("s1.age:"+s1.getAge());

   

       } catch (CloneNotSupportedException e) {

                     e.printStackTrace();

       }

      

    }

运行结果:

student.studentName:xiaobai

student.age:10

s1.studentName:xiaohei

s1.age:10

我们发现s1的studentName值得到了修改,但是student的studentName值没有受到影响,这就是clone的作用。使用起来很简单,只需要在需要clone的对象上实现(implements)Cloneable接口,然后再在类中加上clone方法,在方法中只需要调用super.clone()即可,如上例中的部分代码:Student student =  (Student) super.clone(),需要注意clone方法在当前类没有实现Cloneable的情况下可能抛出CloneNotSupportedException,所以我们需要对该异常进行处理。以上的Student类中只有基本属性,这种拷贝被称为浅拷贝。

 

 

 

深拷贝

如果对象中有其他对象的引用,使用浅拷贝无法完成对象的整个克隆,因为如果使用浅拷贝,只是对象的引用得到的拷贝,而两个引用是指向了同一个对象,对其中一个修改还是会影响到另外一个对象。这时后我们需要引入深拷贝,深拷贝实现起来也比较简单,只需要对对象中的对象再次进行clone操作。看以下实例

 

Glasses类代码如下:

 

public class Glasses implements Cloneable {

 

    private String color;

 

    public String getColor() {

       return color;

    }

 

    public void setColor(String color) {

       this.color = color;

    }

 

 

    protected Object clone() throws CloneNotSupportedException {

      

       return super.clone();

    }

   

}

 

在Student类中包含Glasses,代码如下:

 

public class Student implements Cloneable{

 

    private String studentName;

 

    private Glasses glasses;

   

    private int age;

   

    public int getAge() {

       return age;

    }

 

    public void setAge(int age) {

       this.age = age;

    }

 

    public String getStudentName() {

       return studentName;

    }

 

    public void setStudentName(String studentName) {

       this.studentName = studentName;

    }

 

   

    public Glasses getGlasses() {

       return glasses;

    }

 

    public void setGlasses(Glasses glasses) {

       this.glasses = glasses;

    }

 

    protected Object clone() throws CloneNotSupportedException {

      

       Student student =  (Student) super.clone();

      

       student.glasses=   (Glasses) glasses.clone();

      

       return student;

      

    }

   

}

 

如果想对Glasses进行拷贝,而不是仅仅克隆Glasses的引用,在clone方法中增加了student.glasses=   (Glasses) glasses.clone();

 

 

入口函数:

    public static void main(String args[]){

      

       Student student = new Student();

       student.setAge(10);

       student.setStudentName("xiaobai");

      

       Glasses glasses = new Glasses();

      

       glasses.setColor("red");

      

       student.setGlasses(glasses);

      

       try {

           Student s1  = (Student) student.clone();

           s1.setStudentName("xiaohei");

                 

           System.out.println("s1.color:"+s1.getGlasses().getColor());

       } catch (CloneNotSupportedException e) {

          

           e.printStackTrace();

       }

 

    }

 

运行输出:

s1.color:red

 

通过以上实例,可以看出student中Glasses的color值被完全克隆给了s1,所以s1的Glasses的color也是red。