您的位置:首页 > 编程语言 > Java开发

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

2012-06-02 21:53 501 查看
我们先从理论上讨论浅拷贝:

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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: