引言
对象拷贝(Object Copy)就是将一个对象的属性拷贝到另一个有着相同类类型的对象中去。在程序中拷贝对象是很常见的,主要是为了在新的上下文环境中复用对象的部分或全部 数据。Java中有三种类型的对象拷贝:浅拷贝(Shallow Copy)、深拷贝(Deep Copy)、延迟拷贝(Lazy Copy)。
什么是浅拷贝
浅拷贝是按位拷贝对象,它会创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。如果属性是基本类型,拷贝的就是基本类型的值;如果属性是内存地址(引用类型),拷贝的就是内存地址 ,因此如果其中一个对象改变了这个地址,就会影响到另一个对象。
例子
// 假定每个班级对应唯一的一个班主任,每个班主任对应唯一的一个班级
public static class SchoolClass implements Cloneable {
/**
* 班级名称
*/
public String mClassName;
/**
* 班主任,
*/
public Teacher mTeacher;
public SchoolClass(String className, Teacher teacher) {
mClassName = className;
mTeacher = teacher;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
@Override
public String toString() {
return "SchoolClass{" +
"mClassName='" + mClassName + '\'' +
", mTeacher=" + mTeacher.toString() +
'}';
}
}
public static class Teacher implements Cloneable {
public String name;
public String age;
public Teacher(String name, String age) {
this.name = name;
this.age = age;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
@Override
public String toString() {
return "Teacher{" +
"name='" + name + '\'' +
", age='" + age + '\'' +
'}';
}
}
public static void main(String[] args) throws CloneNotSupportedException {
SchoolClass sc1 = new SchoolClass("3.7", new Teacher("li", "30"));
LogUtil.sysopl("sc1= " + sc1.toString());
SchoolClass sc2 = (SchoolClass) sc1.clone();
sc2.mClassName = "2.8";
sc2.mTeacher.name = "liu";
sc2.mTeacher.age = "25";
LogUtil.sysopl("sc1= " + sc1.toString());
LogUtil.sysopl("sc2= " + sc2.toString());
}
打印结果
sc1= SchoolClass{mClassName='3.7', mTeacher=Teacher{name='li', age='30'}}
sc1= SchoolClass{mClassName='3.7', mTeacher=Teacher{name='liu', age='25'}}
sc2= SchoolClass{mClassName='2.8', mTeacher=Teacher{name='liu', age='25'}}
什么是深拷贝
深拷贝会拷贝所有的属性,并拷贝属性指向的动态分配的内存。当对象和它所引用的对象一起拷贝时即发生深拷贝。深拷贝相比于浅拷贝速度较慢并且花销较大。
例子
public static class SchoolClass implements Cloneable {
/**
* 班级名称
*/
public String mClassName;
/**
* 班主任,
*/
public Teacher mTeacher;
public SchoolClass(String className, Teacher teacher) {
mClassName = className;
mTeacher = teacher;
}
@Override
protected Object clone() throws CloneNotSupportedException {
SchoolClass schoolClass = (SchoolClass) super.clone();
schoolClass.mTeacher = (Teacher) schoolClass.mTeacher.clone();
return schoolClass;
}
@Override
public String toString() {
return "SchoolClass{" +
"mClassName='" + mClassName + '\'' +
", mTeacher=" + mTeacher +
'}';
}
}
public static class Teacher implements Cloneable {
public String name;
public String age;
public Teacher(String name, String age) {
this.name = name;
this.age = age;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
@Override
public String toString() {
return "Teacher{" +
"name='" + name + '\'' +
", age='" + age + '\'' +
'}';
}
}
public static void main(String[] args) throws CloneNotSupportedException {
SchoolClass sc1 = new SchoolClass("3.7", new Teacher("li", "30"));
LogUtil.sysopl("sc1= " + sc1.toString());
SchoolClass sc2 = (SchoolClass) sc1.clone();
sc2.mClassName = "2.8";
sc2.mTeacher.name = "liu";
sc2.mTeacher.age = "25";
LogUtil.sysopl("sc1= " + sc1.toString());
LogUtil.sysopl("sc2= " + sc2.toString());
}
打印结果
sc1= SchoolClass{mClassName='3.7', mTeacher=Teacher{name='li', age='30'}}
sc1= SchoolClass{mClassName='3.7', mTeacher=Teacher{name='li', age='30'}}
sc2= SchoolClass{mClassName='2.8', mTeacher=Teacher{name='liu', age='25'}}
通过序列化实现深拷贝
也可以通过序列化来实现深拷贝。序列化是干什么的?它将整个对象图写入到一个持久化存储文件中并且当需要的时候把它读取回来, 这意味着当你需要把它读取回来时你需要整个对象图的一个拷贝。这就是当你深拷贝一个对象时真正需要的东西。请注意,当你通过序列化进行深拷贝时,必须确保对象图中所有类都是可序列化的。
这种方式会很消耗性能
延迟拷贝
延迟拷贝是浅拷贝和深拷贝的一个组合,实际上很少会使用。 当最开始拷贝一个对象时,会使用速度较快的浅拷贝,还会使用一个计数器来记录有多少对象共享这个数据。当程序想要修改原始的对象时,它会决定数据是否被共享(通过检查计数器)并根据需要进行深拷贝。
参考:
https://blog.csdn.net/wangnanwlw/article/details/52300117
https://www.cnblogs.com/acode/p/6306887.html