zoukankan      html  css  js  c++  java
  • Java的clone():深复制与浅复制

    Java中要想自定义类的对象可以被复制,自定义类就必须实现Cloneable中的clone()方法,如下:

     1 public class Student implements Cloneable {
     2     
     3     private String name;
     4     
     5     private int age;
     6     
     7     private Professor professor;
     8 
     9     public String getName() {
    10         return name;
    11     }
    12 
    13     public void setName(String name) {
    14         this.name = name;
    15     }
    16 
    17     public int getAge() {
    18         return age;
    19     }
    20 
    21     public void setAge(int age) {
    22         this.age = age;
    23     }
    24 
    25     public Professor getProfessor() {
    26         return professor;
    27     }
    28 
    29     public void setProfessor(Professor professor) {
    30         this.professor = professor;
    31     }
    32 
    33     @Override
    34     public String toString() {
    35         return "Student [name=" + name + ", age=" + age + ", professor="
    36                 + professor + "]";
    37     }
    38     
    39     public Object clone() throws CloneNotSupportedException{
    40         return super.clone();
    41     }
    42 
    43 }

    其中,Professor类同样为自定义类:

    public class Professor {
    
        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;
        }
    
        @Override
        public String toString() {
            return "Professor [name=" + name + ", age=" + age + "]";
        }
    
    }

    然而,当自定义类的字段的类型不是基本数据类型时,上面实现了clone()方法会导致问题,不信看下面的代码:

    【程序实例1】

     1 public class ShadowCopy {
     2 
     3     public static void main(String[] args) {
     4         Professor p1 = new Professor();
     5         p1.setName("Professor Zhang");
     6         p1.setAge(30);
     7 
     8         Student s1 = new Student();
     9         s1.setName("xiao ming");
    10         s1.setAge(18);
    11         s1.setProfessor(p1);
    12 
    13         System.out.println(s1);
    14 
    15         try {
    16             Student s2 = (Student) s1.clone();
    17             Professor p2 = s2.getProfessor();
    18             p2.setName("Professor Li");
    19             p2.setAge(45);
    20             s2.setProfessor(p2);
    21             System.out.println("复制后的:s1 = " + s1);
    22             System.out.println("复制后的:s2 = " + s2);
    23         } catch (CloneNotSupportedException e) {
    24             e.printStackTrace();
    25         }
    26 
    27     }
    28 
    29 }

    【运行结果1】

    1 Student [name=xiao ming, age=18, professor=Professor [name=Professor Zhang, age=30]]
    2 复制后的:s1 = Student [name=xiao ming, age=18, professor=Professor [name=Professor Li, age=45]]
    3 复制后的:s2 = Student [name=xiao ming, age=18, professor=Professor [name=Professor Li, age=45]]

    【结果分析】

    学生s1的导师为30岁的Professor Zhang,恰好学生s2与学生s1同名同岁,但是s2的导师为45岁的Professor Li,于是我们顺理成章地复制复制s1并复制给s2,再修改下s2的导师的信息。可是,问题出现了,当我们修改了s2的导师后,s2的信息是对了,但是s1的导师信息也跟着修改了,这可不是我们期望的。

    【问题分析】

    程序实例1中的问题出在哪儿呢?我们已经对Student类实现了clone()方法,怎么还是出问题了呢?我们在看下面的代码:

    【程序实例2】

     1 public class ShadowCopy {
     2 
     3     public static void main(String[] args) {
     4         Professor p1 = new Professor();
     5         p1.setName("Professor Zhang");
     6         p1.setAge(30);
     7 
     8         Student s1 = new Student();
     9         s1.setName("xiao ming");
    10         s1.setAge(18);
    11         s1.setProfessor(p1);
    12 
    13         System.out.println(s1);
    14 
    15         try {
    16             Student s2 = (Student) s1.clone();
    17             s2.setName("xiao hong");
    18             s2.setAge(17);
    19             Professor p2 = s2.getProfessor();
    20             p2.setName("Professor Li");
    21             p2.setAge(45);
    22             s2.setProfessor(p2);
    23             System.out.println("复制后的:s1 = " + s1);
    24             System.out.println("复制后的:s2 = " + s2);
    25         } catch (CloneNotSupportedException e) {
    26             e.printStackTrace();
    27         }
    28 
    29     }
    30 
    31 }

    【运行结果】

    1 Student [name=xiao ming, age=18, professor=Professor [name=Professor Zhang, age=30]]
    2 复制后的:s1 = Student [name=xiao ming, age=18, professor=Professor [name=Professor Li, age=45]]
    3 复制后的:s2 = Student [name=xiao hong, age=17, professor=Professor [name=Professor Li, age=45]]

    【结果分析】

    这次,我们在clone后,又修改了s2的name和age,从结果可以看出,s1的name和age并没有因为s2的修改而改变。

    结合程序实例1和程序实例2,我们发现Student的字段如果不是一个引用时,修改clone()得到对象的该字段(name, age)时并不会影响原来的对象,但是当字段为一个引用时,修改clone()得到对象的该字段(professor)时并会影响原来的对象。上面实现的clone()方法为浅复制(shadow copy)。

    如果想要clone()得到的新对象的修改不会影响被复制的对象的字段时,我们就需要实现深复制(deep copy),代码修改如下:

     1 public class Professor implements Cloneable {
     2 
     3     private String name;
     4 
     5     private int age;
     6 
     7     public String getName() {
     8         return name;
     9     }
    10 
    11     public void setName(String name) {
    12         this.name = name;
    13     }
    14 
    15     public int getAge() {
    16         return age;
    17     }
    18 
    19     public void setAge(int age) {
    20         this.age = age;
    21     }
    22     
    23     @Override
    24     public String toString() {
    25         return "Professor [name=" + name + ", age=" + age + "]";
    26     }
    27 
    28     public Object clone() throws CloneNotSupportedException{
    29         return super.clone();
    30     }
    31 
    32 }
    public class Student implements Cloneable {
        
        private String name;
        
        private int age;
        
        private Professor professor;
    
        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 Professor getProfessor() {
            return professor;
        }
    
        public void setProfessor(Professor professor) {
            this.professor = professor;
        }
    
        @Override
        public String toString() {
            return "Student [name=" + name + ", age=" + age + ", professor="
                    + professor + "]";
        }
        
        public Object clone() throws CloneNotSupportedException{
            Student newStudent = (Student) super.clone();
            newStudent.professor = (Professor) professor.clone();
            return newStudent;
        }
    
    }

    再次运行【程序实例2】得到的结果为:

    1 Student [name=xiao ming, age=18, professor=Professor [name=Professor Zhang, age=30]]
    2 复制后的:s1 = Student [name=xiao ming, age=18, professor=Professor [name=Professor Zhang, age=30]]
    3 复制后的:s2 = Student [name=xiao hong, age=17, professor=Professor [name=Professor Li, age=45]]

    可以看到:修改clone()得到的s2的任何字段都不会影响s1的字段,这也就是深复制的作用。

    参考资料:

    1、http://pengcqu.iteye.com/blog/493120

    2、http://www.cnblogs.com/shuaiwhu/archive/2010/12/14/2065088.html

  • 相关阅读:
    Adobe Photoshop cs6 破解方法
    vs2008试用90天破解方法
    Install win8_pro using UltraISO
    面试题-100盏灯问题
    PHP 博客文集 1 Veda原型 成功,唯有积累,没有奇迹
    php 框架
    php 语法2
    干货 连接
    试题 极客学院
    地图
  • 原文地址:https://www.cnblogs.com/acode/p/6306887.html
Copyright © 2011-2022 走看看