java中的clone()方法,浅拷贝和深拷贝

http://blog.youkuaiyun.com/puppylpg/article/details/45706417

http://blog.youkuaiyun.com/centre10/article/details/6847973



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

所以我们要进行深拷贝!

浅拷贝和深拷贝例子:

[java]  view plain  copy
  1. import java.util.Vector;  
  2.   
  3. public class Student implements Cloneable{  
  4.         private int id;  
  5.         private String name;  
  6.         private Vector courses;  
  7.           
  8.         public Student(){  
  9.             try{  
  10.             Thread.sleep(1000);  
  11.             System.out.println("Student Construnctor called");  
  12.             }catch(InterruptedException e){  
  13.                 e.printStackTrace();  
  14.             }  
  15.         }  
  16.           
  17.         public int getId(){  
  18.             return id;  
  19.         }  
  20.         public void setId(int id){  
  21.             this.id=id;  
  22.         }  
  23.         public String getName(){  
  24.             return name;  
  25.         }  
  26.         public void setName(String name){  
  27.             this.name=name;  
  28.         }  
  29.         public Vector getCourses(){  
  30.             return courses;  
  31.         }  
  32.         public void setCourses(Vector courses){  
  33.             this.courses=courses;  
  34.         }  
  35.           
  36.         public Student newInstance(){   //使用clone()创建对象,浅拷贝  
  37.             try{  
  38.                 return (Student)this.clone();     
  39.             }catch(CloneNotSupportedException e){  
  40.                 e.printStackTrace();  
  41.             }  
  42.             return null;  
  43.         }  
  44.           
  45.         public Student deepClone(){     //使用clone()创建对象,深拷贝  
  46.             try{  
  47.                 Student cloning = (Student) super.clone();  
  48. //              Student cloning = (Strdent) this.clone();   //和上一句话效果等价  
  49.                 cloning.courses = new Vector();     //关键点:非基本数据类型的空间需要自己新开辟一块儿  
  50.                 return cloning;  
  51.             }catch(CloneNotSupportedException e){  
  52.                 e.printStackTrace();  
  53.             }  
  54.             return null;  
  55.         }  
  56.   
  57. }  
[java]  view plain  copy
  1. import java.util.Vector;  
  2.   
  3.   
  4. public class Test {  
  5.   
  6.     public static void main(String[] args) {  
  7.         // TODO Auto-generated method stub  
  8.         Student stu1 = null;  
  9.   
  10.         shallowCopyDemo(stu1);  
  11.         System.out.println("----- ----- -----I'm cut-off rule----- ----- -----");  
  12.         deepCopyDemo(stu1);  
  13.   
  14.     }  
  15.   
  16.     public static void shallowCopyDemo(Student stu1) {  
  17.         stu1=new Student();  
  18.         Vector cs=new Vector();  
  19.         cs.add("Java");  
  20.         stu1.setId(1);  
  21.         stu1.setName("Tom");  
  22.         stu1.setCourses(cs);  
  23.           
  24.         Student stu2=stu1.newInstance();  
  25.         stu2.setId(2);  
  26.         stu2.setName("Mary");  
  27.         stu2.getCourses().add("C#");  
  28.   
  29.         System.out.println("stu1'name:"+stu1.getName());  
  30.         System.out.println("stu2'name:"+stu2.getName());  
  31.         System.out.println(stu1.getCourses()==stu2.getCourses());  
  32.         System.out.println(stu1.getName + "'s course: " + stu1.getCourses());  
  33.         System.out.println(stu2.getName + "'s course: " + stu2.getCourses());  
  34.     }  
  35.   
  36.     public static void deepCopyDemo(Student stu1) {  
  37.         stu1=new Student();  
  38.         Vector cs=new Vector();  
  39.         cs.add("Java");  
  40.         stu1.setId(1);  
  41.         stu1.setName("Tom");  
  42.         stu1.setCourses(cs);  
  43.           
  44.         Student stu2=stu1.deepClone();  
  45.         stu2.setId(2);  
  46.         stu2.setName("Mary");  
  47.         stu2.getCourses().add("C#");  
  48.   
  49.         System.out.println("stu1'name:"+stu1.getName());  
  50.         System.out.println("stu2'name:"+stu2.getName());  
  51.         System.out.println(stu1.getCourses()==stu2.getCourses());  
  52.         System.out.println(stu1.getName + "'s course: " + stu1.getCourses());  
  53.         System.out.println(stu2.getName + "'s course: " + stu2.getCourses());  
  54.     }  
  55.   
  56. }  


输出结果:


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 = (Student) this.clone()都是可行的。除此之外,我们也可以直接覆写本类的clone()函数这样的话就只能使用Student cloning = (Student) super.clone()了,覆写的代码如下:

[java]  view plain  copy
  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 = (Student) this.clone()的原因是我们正在覆写本类的clone()方法,如果再调用本类的函数,即:this.clone(),就相当于无限递归无限死循环了,最终肯定会崩溃的。所以这里我们只能调用父类的函数,即:super.clone()。

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


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值