首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java中的clone() 深拷贝 浅拷贝

Java中的clone() 深拷贝 浅拷贝

作者头像
哲洛不闹
发布2018-09-19 11:33:08
1.1K0
发布2018-09-19 11:33:08
举报

上图展示了浅拷贝:对于非基本数据类型,clone过后,结果两个指针指向了同一块儿内存空间,所以仅仅是浅拷贝,这样的话如果对一个对象进行操作,另一个内容也会变,这显然是不合理的,应该每个对象分别保存自己的数据。

所以我们要进行深拷贝!

浅拷贝和深拷贝例子:

[java] view plaincopy

  1. import java.util.Vector;
  2. public class Student implements Cloneable{
  3. private int id;
  4. private String name;
  5. private Vector courses;
  6. public Student(){
  7. try{
  8. Thread.sleep(1000);
  9. System.out.println("Student Construnctor called");
  10. }catch(InterruptedException e){
  11. e.printStackTrace();
  12. }
  13. }
  14. public int getId(){
  15. return id;
  16. }
  17. public void setId(int id){
  18. this.id=id;
  19. }
  20. public String getName(){
  21. return name;
  22. }
  23. public void setName(String name){
  24. this.name=name;
  25. }
  26. public Vector getCourses(){
  27. return courses;
  28. }
  29. public void setCourses(Vector courses){
  30. this.courses=courses;
  31. }
  32. public Student newInstance(){ //使用clone()创建对象,浅拷贝
  33. try{
  34. return (Student)this.clone();
  35. }catch(CloneNotSupportedException e){
  36. e.printStackTrace();
  37. }
  38. return null;
  39. }
  40. public Student deepClone(){ //使用clone()创建对象,深拷贝
  41. try{
  42. Student cloning = (Student) super.clone();
  43. // Student cloning = (Strdent) this.clone(); //和上一句话效果等价
  44. cloning.courses = new Vector(); //关键点:非基本数据类型的空间需要自己新开辟一块儿
  45. return cloning;
  46. }catch(CloneNotSupportedException e){
  47. e.printStackTrace();
  48. }
  49. return null;
  50. }
  51. }

[java] view plaincopy

  1. import java.util.Vector;
  2. public class Test {
  3. public static void main(String[] args) {
  4. // TODO Auto-generated method stub
  5. Student stu1 = null;
  6. shallowCopyDemo(stu1);
  7. System.out.println("----- ----- -----I'm cut-off rule----- ----- -----");
  8. deepCopyDemo(stu1);
  9. }
  10. public static void shallowCopyDemo(Student stu1) {
  11. stu1=new Student();
  12. Vector cs=new Vector();
  13. cs.add("Java");
  14. stu1.setId(1);
  15. stu1.setName("Tom");
  16. stu1.setCourses(cs);
  17. Student stu2=stu1.newInstance();
  18. stu2.setId(2);
  19. stu2.setName("Mary");
  20. stu2.getCourses().add("C#");
  21. System.out.println("stu1'name:"+stu1.getName());
  22. System.out.println("stu2'name:"+stu2.getName());
  23. System.out.println(stu1.getCourses()==stu2.getCourses());
  24. System.out.println(stu1.getName + "'s course: " + stu1.getCourses());
  25. System.out.println(stu2.getName + "'s course: " + stu2.getCourses());
  26. }
  27. public static void deepCopyDemo(Student stu1) {
  28. stu1=new Student();
  29. Vector cs=new Vector();
  30. cs.add("Java");
  31. stu1.setId(1);
  32. stu1.setName("Tom");
  33. stu1.setCourses(cs);
  34. Student stu2=stu1.deepClone();
  35. stu2.setId(2);
  36. stu2.setName("Mary");
  37. stu2.getCourses().add("C#");
  38. System.out.println("stu1'name:"+stu1.getName());
  39. System.out.println("stu2'name:"+stu2.getName());
  40. System.out.println(stu1.getCourses()==stu2.getCourses());
  41. System.out.println(stu1.getName + "'s course: " + stu1.getCourses());
  42. System.out.println(stu2.getName + "'s course: " + stu2.getCourses());
  43. }
  44. }

输出结果:

Student Construnctor called stu1'name:Tom stu2'name:Mary true Tom's course: [Java, C#] Mary's course: [Java, C#] ----- ----- -----I'm cut-off rule----- ----- ----- Student Construnctor called stu1'name:Tom stu2'name:Mary false Tom's course: [Java] Mary's course: [C#]

由结果可知,第一种调用浅拷贝导致对Mary添加课程C#的时候,Tom的课程中竟然 也有了C#,而且Mary的课程中也有Tom的Java,且stu1.getCourses()==stu2.getCourses()返回的是 “true”,说明二者的course属性指向的就是同一块儿内存;而在第二种情况中,我们为copy出来的Mary的course新开辟了一块儿空间 cloning.courses = new Vector(),所以Tom和Mary操控的是不同的Vector内存,两者自然就不一样了。

在上例中,深拷贝deepClone()和浅拷贝newInstance()函数都是 我们自己写的,所以deepClone()的Student cloning = (Student) super.clone()和Student cloning = (Strdent) this.clone()都是可行的。除此之外,我们也可以直接覆写本类的clone()函数这样的话就只能使用Student cloning = (Student) super.clone()了,覆写的代码如下:

[java] view plaincopy

  1. public Object clone(){ //覆写clone(),深拷贝
  2. try{
  3. Student cloning = (Student) super.clone();
  4. cloning.courses = new Vector(); //关键点:非基本数据类型的空间需要自己新开辟一块儿
  5. return cloning;
  6. }catch(CloneNotSupportedException e){
  7. e.printStackTrace();
  8. }
  9. return null;
  10. }

这里不能使用Student cloning = (Strdent) this.clone()的原因是我们正在覆写本类的clone()方法,如果再调用本类的函数,即:this.clone(),就相当于无线递归无限死循环了,最终肯定会崩溃的。所以这里我们只能调用父类的函数,即:super.clone()。

所以,要么自己给自己的深拷贝函数起一个名字,要么覆写本类的clone()方法,自己选一个就好,但两者的关键都在于——对于非基本数据类型,要重新new一块儿空间。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2015-05-14,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 java一日一条 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档