博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Java的clone():深复制与浅复制
阅读量:2069 次
发布时间:2019-04-29

本文共 6080 字,大约阅读时间需要 20 分钟。

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     @Override34     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     @Override24     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的字段,这也就是深复制的作用。

转载地址:http://hccmf.baihongyu.com/

你可能感兴趣的文章
Java网络编程与NIO详解8:浅析mmap和Direct Buffer
查看>>
Java网络编程与NIO详解10:深度解读Tomcat中的NIO模型
查看>>
Java网络编程与NIO详解11:Tomcat中的Connector源码分析(NIO)
查看>>
深入理解JVM虚拟机1:JVM内存的结构与消失的永久代
查看>>
深入理解JVM虚拟机3:垃圾回收器详解
查看>>
深入理解JVM虚拟机4:Java class介绍与解析实践
查看>>
深入理解JVM虚拟机5:虚拟机字节码执行引擎
查看>>
深入理解JVM虚拟机6:深入理解JVM类加载机制
查看>>
深入了解JVM虚拟机8:Java的编译期优化与运行期优化
查看>>
深入理解JVM虚拟机9:JVM监控工具与诊断实践
查看>>
深入理解JVM虚拟机10:JVM常用参数以及调优实践
查看>>
深入理解JVM虚拟机12:JVM性能管理神器VisualVM介绍与实战
查看>>
深入理解JVM虚拟机13:再谈四种引用及GC实践
查看>>
Spring源码剖析1:Spring概述
查看>>
Spring源码剖析2:初探Spring IOC核心流程
查看>>
Spring源码剖析5:JDK和cglib动态代理原理详解
查看>>
Spring源码剖析6:Spring AOP概述
查看>>
【Linux】进程的理解(二)
查看>>
【Linux】vim的简单配置
查看>>
ThreadLocal 那点事儿(续集)
查看>>