一、概念辨析
浅拷贝是只拷贝源对象中的非对象属性(基本类型属性),对于对象属性,只拷贝它们的引用。同时,对于那些不可变的对象属性,如String类属性,修改这些属性并不会影响源对象中的这些属性值。
深拷贝不仅复制主对象,还复制它所引用的对象。
二、实现方式
1、浅拷贝需要类实现cloneable接口,并覆写clone方法,方法体中返回super.clone();
如下所示:
class Student implements Cloneable{
private String name;
private int age;
private Teacher teacher;
//getter,setter,构造方法略
@Override
public Object clone() throws CloneNotSupportedException {//浅拷贝
return super.clone();
}
使用方法:
Student stu1 = new Student("xiaowang", 25, teacher);
Student stu2 = stu1.clone();
2、深拷贝有两种实现方式,一种是对象、对象的对象等逐层实现cloneable接口并覆写clone方法,同时在覆写时,要通过对象属性的clone方法重新对对象属性赋值,这样才能生成一个新的对象属性。该方法的缺点在于,如果对象存在嵌套引用,即对象甲引用对象乙,对象乙又引用对象丙等等,在这样的情况下,每个有引用对象的类都需要实现深拷贝功能;同时如果类中有多个引用对象,那在覆写clone方法时需要对每个对象都进行set。如下所示:
class Student implements Cloneable{
private String name;
private int age;
private Teacher teacher;
//getter,setter,构造方法略
@Override
public Object clone() throws CloneNotSupportedException { //深拷贝
Student student = (Student) super.clone(); //先进行浅拷贝
student.setTeacher((Teacher)student.getTeacher().clone()); //再将student的teacher对象复制一份,
// 这个新的teacher对象再赋给student,这样就实现了对象复制,而不是引用复制了。
return student;
}
第二种是通过将对象序列化,写进一个字节流中,然后再从字节流中读出来,反序列化生成一个新的对象拷贝,即深拷贝。该方法相较于第一种更简单,但是仍需要各对象类逐层实现Serializable接口,这只是一个标记接口,不需要覆写任何方法。如果读者想要试验这种方法,只需要自己写一个类,这个类及它的对象类要实现Serializable接口,然后就可以调用下面的函数实现深拷贝:
public class CloneUtils {
@SuppressWarnings("unchecked")
public static <T extends Serializable> T clone(T obj){ //深拷贝
T cloneObj = null;
try {
//写入字节流
ByteArrayOutputStream out = new ByteArrayOutputStream();
ObjectOutputStream obs = new ObjectOutputStream(out);
obs.writeObject(obj);
obs.close();
//分配内存,写入原始对象,生成新对象
ByteArrayInputStream ios = new ByteArrayInputStream(out.toByteArray());
ObjectInputStream ois = new ObjectInputStream(ios);
//返回生成的新对象
cloneObj = (T) ois.readObject();
ois.close();
} catch (Exception e) {
e.printStackTrace();
}
return cloneObj;
}
}