浅拷贝:把一个对象中所有的非static成员变量(包括对其它对象的引用,java中的引用相当于C/C++中的指针变量)都拷贝一遍,而不拷贝引用所指向的对象
深拷贝:把一个对象中所有的非static成员变量(包括对其它对象的引用)都拷贝一遍,引用所指向的对象也拷贝一份
一个类的对象如果想要具有拷贝的功能,比如符合如下条件:
1.必须实现Cloneable接口(这个接口中没有定义方法,叫做标记接口)
2.重写Object类的clone()方法,该方法实现的是浅拷贝
3.在该类的clone()方法中的第一句,比如调用super.clone()来调用Object的clone()方法来实现拷贝
浅拷贝的例子:
public class CloneTest
{
public static void main(String[] args)
{
Student s1 = new Student();
s1.setAge(20);
s1.setName("wudi");
School school = new School();
school.setName("Peiyang University");
school.setBornYear(1895);
s1.setSchool(school);
System.out
.println("s1:" + s1.getName() + " " + s1.getAge() + " "
+ s1.getSchool().getName() + " "
+ s1.getSchool().getBornYear());
try
{
//拷贝一个学生
Student s2 = (Student)s1.clone();
s2.setAge(21);
s2.setName("WUDI");
System.out
.println("s2:" + s2.getName() + " " + s2.getAge() + " "
+ s2.getSchool().getName() + " "
+ s2.getSchool().getBornYear());
System.out.println("after s2 changing some property:");
//通过学生s2改变了他所在学校的名称和成立时间
s2.getSchool().setName("Tianjin University");
s2.getSchool().setBornYear(1951);
System.out
.println("s1:" + s1.getName() + " " + s1.getAge() + " "
+ s1.getSchool().getName() + " "
+ s1.getSchool().getBornYear());
System.out
.println("s2:" + s2.getName() + " " + s2.getAge() + " "
+ s2.getSchool().getName() + " "
+ s2.getSchool().getBornYear());
}
catch (CloneNotSupportedException e)
{
e.printStackTrace();
}
}
}
class School
{
private String name;
private int bornYear;
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
public int getBornYear()
{
return bornYear;
}
public void setBornYear(int bornYear)
{
this.bornYear = bornYear;
}
}
class Student implements Cloneable
{
private int age;
private String name;
private School school;
public School getSchool()
{
return school;
}
public void setSchool(School school)
{
this.school = school;
}
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
{
return super.clone();
}
}
package com.test;
public class CloneTest
{
public static void main(String[] args)
{
Student s1 = new Student();
s1.setAge(20);
s1.setName("wudi");
School school = new School();
school.setName("Peiyang University");
school.setBornYear(1895);
s1.setSchool(school);
System.out
.println("s1:" + s1.getName() + " " + s1.getAge() + " "
+ s1.getSchool().getName() + " "
+ s1.getSchool().getBornYear());
try
{
//拷贝一个学生
Student s2 = (Student)s1.clone();
s2.setAge(21);
s2.setName("WUDI");
System.out
.println("s2:" + s2.getName() + " " + s2.getAge() + " "
+ s2.getSchool().getName() + " "
+ s2.getSchool().getBornYear());
System.out.println("after s2 changing some property:");
//通过学生s2改变了他所在学校的名称和成立时间
s2.getSchool().setName("Tianjin University");
s2.getSchool().setBornYear(1951);
System.out
.println("s1:" + s1.getName() + " " + s1.getAge() + " "
+ s1.getSchool().getName() + " "
+ s1.getSchool().getBornYear());
System.out
.println("s2:" + s2.getName() + " " + s2.getAge() + " "
+ s2.getSchool().getName() + " "
+ s2.getSchool().getBornYear());
}
catch (CloneNotSupportedException e)
{
e.printStackTrace();
}
}
}
class School
{
private String name;
private int bornYear;
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
public int getBornYear()
{
return bornYear;
}
public void setBornYear(int bornYear)
{
this.bornYear = bornYear;
}
}
class Student implements Cloneable
{
private int age;
private String name;
private School school;
public School getSchool()
{
return school;
}
public void setSchool(School school)
{
this.school = school;
}
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
{
return super.clone();
}
}
从运行结果可以看出,通过学生s2将其引用school所指向的对象的name和bornYear属性改变,相应的s1的也被改变,这说明学生s1和学生s2里面的school引用指向的始终是同一个School对象。这就是浅拷贝的含义。
深拷贝的例子:
public class CloneTest
{
public static void main(String[] args)
{
Student s1 = new Student();
s1.setAge(20);
s1.setName("wudi");
School school = new School();
school.setName("Peiyang University");
school.setBornYear(1895);
s1.setSchool(school);
System.out
.println("s1:" + s1.getName() + " " + s1.getAge() + " "
+ s1.getSchool().getName() + " "
+ s1.getSchool().getBornYear());
try
{
//拷贝一个学生
Student s2 = (Student)s1.clone();
s2.setAge(21);
s2.setName("WUDI");
System.out
.println("s2:" + s2.getName() + " " + s2.getAge() + " "
+ s2.getSchool().getName() + " "
+ s2.getSchool().getBornYear());
System.out.println("after s2 changing some property:");
//通过学生s2改变了他所在学校的名称和成立时间
s2.getSchool().setName("Tianjin University");
s2.getSchool().setBornYear(1951);
System.out
.println("s1:" + s1.getName() + " " + s1.getAge() + " "
+ s1.getSchool().getName() + " "
+ s1.getSchool().getBornYear());
System.out
.println("s2:" + s2.getName() + " " + s2.getAge() + " "
+ s2.getSchool().getName() + " "
+ s2.getSchool().getBornYear());
}
catch (CloneNotSupportedException e)
{
e.printStackTrace();
}
}
}
class School implements Cloneable
{
private String name;
private int bornYear;
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
public int getBornYear()
{
return bornYear;
}
public void setBornYear(int bornYear)
{
this.bornYear = bornYear;
}
@Override
protected Object clone() throws CloneNotSupportedException
{
return super.clone();
}
}
class Student implements Cloneable
{
private int age;
private String name;
private School school;
public School getSchool()
{
return school;
}
public void setSchool(School school)
{
this.school = school;
}
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
{
Student s2 = (Student)super.clone();
//将school所引用的对象也拷贝一份,并且让学生s2去引用这个新的School对象
s2.setSchool((School)school.clone());
return s2;
}
}
package com.test;
public class CloneTest
{
public static void main(String[] args)
{
Student s1 = new Student();
s1.setAge(20);
s1.setName("wudi");
School school = new School();
school.setName("Peiyang University");
school.setBornYear(1895);
s1.setSchool(school);
System.out
.println("s1:" + s1.getName() + " " + s1.getAge() + " "
+ s1.getSchool().getName() + " "
+ s1.getSchool().getBornYear());
try
{
//拷贝一个学生
Student s2 = (Student)s1.clone();
s2.setAge(21);
s2.setName("WUDI");
System.out
.println("s2:" + s2.getName() + " " + s2.getAge() + " "
+ s2.getSchool().getName() + " "
+ s2.getSchool().getBornYear());
System.out.println("after s2 changing some property:");
//通过学生s2改变了他所在学校的名称和成立时间
s2.getSchool().setName("Tianjin University");
s2.getSchool().setBornYear(1951);
System.out
.println("s1:" + s1.getName() + " " + s1.getAge() + " "
+ s1.getSchool().getName() + " "
+ s1.getSchool().getBornYear());
System.out
.println("s2:" + s2.getName() + " " + s2.getAge() + " "
+ s2.getSchool().getName() + " "
+ s2.getSchool().getBornYear());
}
catch (CloneNotSupportedException e)
{
e.printStackTrace();
}
}
}
class School implements Cloneable
{
private String name;
private int bornYear;
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
public int getBornYear()
{
return bornYear;
}
public void setBornYear(int bornYear)
{
this.bornYear = bornYear;
}
@Override
protected Object clone() throws CloneNotSupportedException
{
return super.clone();
}
}
class Student implements Cloneable
{
private int age;
private String name;
private School school;
public School getSchool()
{
return school;
}
public void setSchool(School school)
{
this.school = school;
}
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
{
Student s2 = (Student)super.clone();
//将school所引用的对象也拷贝一份,并且让学生s2去引用这个新的School对象
s2.setSchool((School)school.clone());
return s2;
}
}
该段代码让School类(被引用的类)也实现了Cloneable接口,并且也重写了clone()方法。然后改写了Student的clone()方法。从结果可以看出,学生s2改变其引用的学校的属性,不会影响到学生s1所属的学校的属性,这就是深拷贝的含义。还可以通过序列化来实现对象的深拷贝,一个对象被序列化时会将对象和对象内部引用的其他的对象(递归下去)一起序列化一个对象如果想要被序列化,那么必须实现Serializable接口,这个接口也没有定义任何方法,也是一个marker interface
将前一个例子进行改写,用序列化的方法实现深拷贝的代码如下:
view plaincopy to clipboardprint?
package com.test;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
public class CloneTest
{
public static void main(String[] args) throws Exception
{
Student s1 = new Student();
s1.setAge(20);
s1.setName("wudi");
School school = new School();
school.setName("Peiyang University");
school.setBornYear(1895);
s1.setSchool(school);
System.out
.println("s1:" + s1.getName() + " " + s1.getAge() + " "
+ s1.getSchool().getName() + " "
+ s1.getSchool().getBornYear());
try
{
//拷贝一个学生
Student s2 = (Student)s1.deepClone();
s2.setAge(21);
s2.setName("WUDI");
System.out
.println("s2:" + s2.getName() + " " + s2.getAge() + " "
+ s2.getSchool().getName() + " "
+ s2.getSchool().getBornYear());
System.out.println("after s2 changing some property:");
//通过学生s2改变了他所在学校的名称和成立时间
s2.getSchool().setName("Tianjin University");
s2.getSchool().setBornYear(1951);
System.out
.println("s1:" + s1.getName() + " " + s1.getAge() + " "
+ s1.getSchool().getName() + " "
+ s1.getSchool().getBornYear());
System.out
.println("s2:" + s2.getName() + " " + s2.getAge() + " "
+ s2.getSchool().getName() + " "
+ s2.getSchool().getBornYear());
}
catch (CloneNotSupportedException e)
{
e.printStackTrace();
}
}
}
class School implements Serializable
{
private String name;
private int bornYear;
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
public int getBornYear()
{
return bornYear;
}
public void setBornYear(int bornYear)
{
this.bornYear = bornYear;
}
}
class Student implements Serializable
{
private int age;
private String name;
private School school;
public School getSchool()
{
return school;
}
public void setSchool(School school)
{
this.school = school;
}
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 Object deepClone() throws Exception
{
ByteArrayOutputStream baos = new ByteArrayOutputStream();
//相当于流的连接,将oos流对象连接到baos流对象
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(this);//以上三行将this对象序列化后输出到baos对象中
//将baos这个流对象转化成字节数组,然后利用这个字节数组构造bais对象
//下面三行就是一个反序列化的过程
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bais);
return ois.readObject();
}
}