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

技术分享

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

所以我们要进行深拷贝!

浅拷贝和深拷贝例子:

import java.util.Vector;

public class Student implements Cloneable{
		private int id;
		private String name;
		private Vector courses;
		
		public Student(){
			try{
			Thread.sleep(1000);
			System.out.println("Student Construnctor called");
			}catch(InterruptedException e){
				e.printStackTrace();
			}
		}
		
		public int getId(){
			return id;
		}
		public void setId(int id){
			this.id=id;
		}
		public String getName(){
			return name;
		}
		public void setName(String name){
			this.name=name;
		}
		public Vector getCourses(){
			return courses;
		}
		public void setCourses(Vector courses){
			this.courses=courses;
		}
		
		public Student newInstance(){   //使用clone()创建对象,浅拷贝
			try{
				return (Student)this.clone();	
			}catch(CloneNotSupportedException e){
				e.printStackTrace();
			}
			return null;
		}
		
		public Student deepClone(){		//使用clone()创建对象,深拷贝
			try{
				Student cloning = (Student) super.clone();
//				Student cloning = (Strdent) this.clone();	//和上一句话效果等价
				cloning.courses = new Vector();		//关键点:非基本数据类型的空间需要自己新开辟一块儿
				return cloning;
			}catch(CloneNotSupportedException e){
				e.printStackTrace();
			}
			return null;
		}

}
import java.util.Vector;


public class Test {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Student stu1 = null;

		shallowCopyDemo(stu1);
		System.out.println("----- ----- -----I'm cut-off rule----- ----- -----");
		deepCopyDemo(stu1);

	}

	public static void shallowCopyDemo(Student stu1) {
		stu1=new Student();
		Vector cs=new Vector();
		cs.add("Java");
		stu1.setId(1);
		stu1.setName("Tom");
		stu1.setCourses(cs);
		
		Student stu2=stu1.newInstance();
		stu2.setId(2);
		stu2.setName("Mary");
		stu2.getCourses().add("C#");

		System.out.println("stu1'name:"+stu1.getName());
		System.out.println("stu2'name:"+stu2.getName());
		System.out.println(stu1.getCourses()==stu2.getCourses());
		System.out.println(stu1.getName + "'s course: " + stu1.getCourses());
		System.out.println(stu2.getName + "'s course: " + stu2.getCourses());
	}

	public static void deepCopyDemo(Student stu1) {
		stu1=new Student();
		Vector cs=new Vector();
		cs.add("Java");
		stu1.setId(1);
		stu1.setName("Tom");
		stu1.setCourses(cs);
		
		Student stu2=stu1.deepClone();
		stu2.setId(2);
		stu2.setName("Mary");
		stu2.getCourses().add("C#");

		System.out.println("stu1'name:"+stu1.getName());
		System.out.println("stu2'name:"+stu2.getName());
		System.out.println(stu1.getCourses()==stu2.getCourses());
		System.out.println(stu1.getName + "'s course: " + stu1.getCourses());
		System.out.println(stu2.getName + "'s course: " + stu2.getCourses());
	}

}


输出结果:


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()了,覆写的代码如下:

		public Object clone(){		//覆写clone(),深拷贝
			try{
				Student cloning = (Student) super.clone();
				cloning.courses = new Vector();		//关键点:非基本数据类型的空间需要自己新开辟一块儿
				return cloning;
			}catch(CloneNotSupportedException e){
				e.printStackTrace();
			}
			return null;
		}
这里不能使用Student cloning = (Strdent) this.clone()的原因是我们正在覆写本类的clone()方法,如果再调用本类的函数,即:this.clone(),就相当于无线递归无限死循环了,最终肯定会崩溃的。所以这里我们只能调用父类的函数,即:super.clone()。

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

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。