浅拷贝:
浅拷贝(同一个引用):仅仅复制所考虑的对象,而不复制它所引用的对象。
Object类 是所有类的直接或间接父类,Object中存在clone方法,如下
protected native Object clone() throws CloneNotSupportedException;
如果想要使一个类的对象能够调用clone方法 ,则需要实现Cloneable接口, 并重写 clone方法:
packagecopy;class Teacher implementsCloneable
{privateString name;private intage;publicString getName()
{returnname;
}public voidsetName(String name)
{this.name =name;
}public intgetAge()
{returnage;
}public void setAge(intage)
{this.age =age;
}
}class Student2 implementsCloneable {privateString name;private intage;privateTeacher teacher;publicString getName() {returnname;
}public voidsetName(String name) {this.name =name;
}public intgetAge() {returnage;
}public void setAge(intage) {this.age =age;
}publicTeacher getTeacher() {returnteacher;
}public voidsetTeacher(Teacher teacher) {this.teacher =teacher;
}
@Overridepublic Object clone() throwsCloneNotSupportedException {return super.clone();
}
}public classCopyTest {public static void main(String[] args) throwsCloneNotSupportedException {
Teacher teacher= newTeacher();
teacher.setName("Delacey");
teacher.setAge(29);
Student2 student1= newStudent2();
student1.setName("Dream");
student1.setAge(18);
student1.setTeacher(teacher);
Student2 student2=(Student2) student1.clone();
System.out.println("拷贝后");
System.out.println(student2.getName());//Dream
System.out.println(student2.getAge());//18
System.out.println(student2.getTeacher().getName());//Delacey
System.out.println(student2.getTeacher().getAge());//29
System.out.println("修改老师的信息后------");//修改老师的信息
teacher.setName("Jam");
System.out.println(student1.getTeacher().getName());//Jam
System.out.println(student2.getTeacher().getName());//Jam
System.out.println("修改拷贝后的学生信息后与被拷贝学生信息对比------");
student2.setName("MerGy");
System.out.println(student1.getName());//Dream
System.out.println(student2.getName());//MerGy
}
}
深拷贝:
深拷贝会拷贝独立对象所有的属性,并拷贝属性指向的内存。深拷贝会把要复制的对象和引用的对象都拷贝,所以,深拷贝相比于浅拷贝速度较慢并且花销较大。
package copy;
class Teacher2 implements Cloneable {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
class Student3 implements Cloneable {
private String name;
private int age;
private Teacher2 teacher;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Teacher2 getTeacher() {
return teacher;
}
public void setTeacher(Teacher2 teacher) {
this.teacher = teacher;
}
@Override
public Object clone() throws CloneNotSupportedException {
// 浅复制时:
// return super.clone();
// 改为深复制:
Student3 student = (Student3) super.clone();
// 本来是浅复制,现在将Teacher对象复制一份并重新set进来
student.setTeacher((Teacher2) student.getTeacher().clone());
return student;
}
}
public class CopyTest {
public static void main(String[] args) throws CloneNotSupportedException {
Teacher2 teacher = new Teacher2();
teacher.setName("Delacey");
teacher.setAge(29);
Student3 student1 = new Student3();
student1.setName("Dream");
student1.setAge(18);
student1.setTeacher(teacher);
Student3 student2 = (Student3) student1.clone();
System.out.println("拷贝后");
System.out.println(student2.getName());
System.out.println(student2.getAge());
System.out.println(student2.getTeacher().getName());
System.out.println(student2.getTeacher().getAge());
System.out.println("修改老师的信息后-------------");
// 修改老师的信息
teacher.setName("Jam");
System.out.println(student1.getTeacher().getName());//Jam
System.out.println(student2.getTeacher().getName());//Delacey
}
}
利用序列化实现深拷贝
packageblog;importjava.io.ByteArrayInputStream;importjava.io.ByteArrayOutputStream;importjava.io.ObjectInputStream;importjava.io.ObjectOutputStream;importjava.io.Serializable;
public classDeepCopyServiable {public static void main(String[] args) throwsException {
Teacher3 t= newTeacher3();
t.setName("Taylor");
t.setAge(28);
Student3 s1= newStudent3();
s1.setAge(20);
s1.setName("blank space");
s1.setTeacher(t);
Student3 s2=(Student3) s1.deepClone();
System.out.println("拷贝后:");
System.out.println(s2.getName());
System.out.println(s2.getAge());
System.out.println(s2.getTeacher().getName());
System.out.println(s2.getTeacher().getAge());
System.out.println("---------------------------");
t.setName("swift");
System.out.println("修改后:");
System.out.println(s1.getTeacher().getName());
System.out.println(s2.getTeacher().getName());
}
}class Teacher3 implementsSerializable
{privateString name;private intage;publicString getName()
{returnname;
}public voidsetName(String name)
{this.name =name;
}public intgetAge()
{returnage;
}public void setAge(intage)
{this.age =age;
}
}class Student3 implementsSerializable
{privateString name;private intage;privateTeacher3 teacher;publicString getName()
{returnname;
}public voidsetName(String name)
{this.name =name;
}public intgetAge()
{returnage;
}public void setAge(intage)
{this.age =age;
}publicTeacher3 getTeacher()
{returnteacher;
}public voidsetTeacher(Teacher3 teacher)
{this.teacher =teacher;
}public Object deepClone() throwsException
{//序列化
ByteArrayOutputStream bos = newByteArrayOutputStream();
ObjectOutputStream oos= newObjectOutputStream(bos);
oos.writeObject(this);//反序列化
ByteArrayInputStream bis = newByteArrayInputStream(bos.toByteArray());
ObjectInputStream ois= newObjectInputStream(bis);returnois.readObject();
}
}
重写clone方法 与 通过序列化 两种拷贝方式比较:
clone方法:
优点:速度快,效率高
缺点:在对象引用比较深时,使用此方式比较繁琐
通过序列化:
优点:非常简便的就可以完成深度copy
缺点:由于序列化的过程需要跟磁盘打交道,因此效率会低于clone方式
在java语言中,使用new创建对象与使用clone方法复制一个对象有什么不同?
用new创建对象本意是分配内存。程序到new操作符时,首先去看new操作符后面的类型,因为知道了类型,才能知道要分配多大的内存空间。分配完内存之后,再调用构造函数,填充对象的各个域,这就叫对象的初始化。对象初始化完毕后,可以把引用发布到外部,在外部就可以使用这个引用操纵这个对象。
clone在第一步和new相似,都是分配内存的,调用clone方法时,分配的内存和源对象相同,然后在使用原对象中对应的各个域,填充新对象的域,填充完成之后,clone方法返回,一个新的相同对象就能被创建,同样这个新对象的引用发布到外部。