Java中深拷贝(Deep Clone)与浅拷贝(Shallow Clone)

        我们先从理论上讨论浅拷贝

        java的类型分为两大类,一类为primitive,如int等8种,另一类为引用类型,如String,Object等等。java的引用类型都是存储在堆上的。

        java的浅复制在复制时,对于原始类型的变量,在堆上为其分配一块区间,对于引用类型,在堆上为其对象的引用分配一块区间,这样得到的实际效果是:被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象,即当对其他对象的引用进行改变时,改变的是对象的值,被复制的引用值也发生了变化。换言之,浅复制仅仅复制所考虑的对象,而不复制它所引用的对象

        实例代码如下:

public class CloneTest1
{
	public static void main(String[] args) throws Throwable
	{
		Teacher teacher = new Teacher();
		
		teacher.setAge(34);
		teacher.setName("Teacher chen");
		
		Student student = new Student();
		
		student.setAge(20);
		student.setName("zhangsan");
		student.setTeacher(teacher);
		
		//clone方法返回的是Object类型的对象,即会生成新的对象
		Student student2 = (Student)student.clone();
		
		System.out.println(student2.getAge());
		System.out.println(student2.getName());
		System.out.println(student2.getTeacher().getAge());
		System.out.println(student2.getTeacher().getName());
		
		System.out.println("----------------------------------");
		
		/**
		 * 以下几行说明clone是浅复制(只是复制引用),即复制后两个对象中的teacher属性都指向同一个对象,
		 * 如果把拷贝的对象的teacher属性重新设置,则会影响被拷贝的对象。
		 */
		student2.getTeacher().setName("hello world");
		student2.getTeacher().setAge(44);
		student2.setName("lisi");//不会改变student的属性
		
		System.out.println(student2.getAge());
		System.out.println(student2.getName());
		//student2中的teacher对象也发生了改变
		System.out.println(student2.getTeacher().getAge());
		System.out.println(student2.getTeacher().getName());
		
		System.out.println("----------------------------------");
		
		System.out.println(student.getAge());
		System.out.println(student.getName());
		System.out.println(student.getTeacher().getAge());
		System.out.println(student.getTeacher().getName());
	}
}

class Student implements Cloneable
{
	private int age;
	
	private String name;
	
	private Teacher teacher;

	public Teacher getTeacher()
	{
		return teacher;
	}

	public void setTeacher(Teacher teacher)
	{
		this.teacher = teacher;
	}

	public int getAge()
	{
		return age;
	}

	public void setAge(int age)
	{
		this.age = age;
	}

	public String getName()
	{
		return name;
	}

	public void setName(String name)
	{
		this.name = name;
	}
	
	@Override
	protected Object clone() throws CloneNotSupportedException
	{
		Object object = super.clone();
		
		return object;
	}
}

class Teacher implements Cloneable
{
	private int age;
	
	private String name;

	public int getAge()
	{
		return age;
	}

	public void setAge(int age)
	{
		this.age = age;
	}

	public String getName()
	{
		return name;
	}

	public void setName(String name)
	{
		this.name = name;
	}
}

        再来看看深拷贝

        理论上,深复制对原始类型的操作与浅复制一样,对于引用类型,其既对对象的引用进行复制,也对对象本身进行复制这样得到的实际效果是:当复制的引用值发生变化时,被复制的引用值没有发生变化,实现了深复制。被复制对象的所有变量都含有与原来的对象相同的值,除去那些引用其他对象的变量。那些引用其他对象的变量将指向被复制过的新对象,而不再是原有的那些被引用的对象。换言之,深复制把要复制的对象所引用的对象都复制了一遍。

        实例代码如下:

//深复制
public class CloneTest2
{
	public static void main(String[] args) throws Throwable
	{
		Teacher2 teacher = new Teacher2();
		
		teacher.setAge(40);
		teacher.setName("Teacher zhang");
		
		Student2 s1 = new Student2();
		
		s1.setAge(20);
		s1.setName("zhangsan");
		s1.setTeacher(teacher);
		
		Student2 s2 = (Student2)s1.clone();
		
		System.out.println(s2.getName());
		System.out.println(s2.getAge());
		
		/**
		 * 因为下面Student2中的clone方法也实现了对Teacher对象的拷贝,
		 * 所以在s2中已经拥有了新的Teacher对象,不再是前面传给s1的那个Teacher对象,
		 * 故下面这句只是改变了s1中的那个Teacher对象,而不会改变s2中的那个Teacher对象。
		 */
		teacher.setName("Teacher li");
		
		System.out.println(s1.getTeacher().getName());
		System.out.println(s1.getTeacher().getAge());
		
		System.out.println(s2.getTeacher().getName());
		System.out.println(s2.getTeacher().getAge());
	}
}

class Teacher2 implements Cloneable
{
	private int age;
	
	private String name;

	public int getAge()
	{
		return age;
	}

	public void setAge(int age)
	{
		this.age = age;
	}

	public String getName()
	{
		return name;
	}

	public void setName(String name)
	{
		this.name = name;
	}
	
	//只是为了在其他类中可以调用Teacher中的这个clone方法,所以重写为public
	@Override
	public Object clone() throws CloneNotSupportedException
	{
		return super.clone();
	}
}

class Student2 implements Cloneable
{
	private int age;
	
	private String name;
	
	private Teacher2 teacher;

	public int getAge()
	{
		return age;
	}

	public void setAge(int age)
	{
		this.age = age;
	}

	public String getName()
	{
		return name;
	}

	public void setName(String name)
	{
		this.name = name;
	}

	public Teacher2 getTeacher()
	{
		return teacher;
	}

	public void setTeacher(Teacher2 teacher)
	{
		this.teacher = teacher;
	}
	
	@Override
	public Object clone() throws CloneNotSupportedException
	{
		Student2 student2 = (Student2)super.clone();
		
		//把Teacher对象也复制一份,相当于有两个Teacher对象了
		student2.setTeacher((Teacher2)student2.getTeacher().clone());
		
		return student2;
		
		//下面这种方法只能实现浅复制
//		Object object = super.clone();
//		
//		return object;
	}
}


        一言以蔽之:浅复制只是简单的值传递(这样一来复制的双方可能有瓜葛),而深复制则是深层次的对象传递(这样一来复制的双方不会有作何瓜葛),这里的对象传递指的是若有引用的复制则生成新的对象,而不会只是单纯地将引用指向原来的对象。


        参考文献:http://java.chinaitlab.com/oop/716567.html


你可能感兴趣的:(Java基础)