11、cloneable接口实现原理,深拷贝和浅拷贝
在开发过程中,拷贝实例是常见的一种操作,如果一个类中的字段较多,而我们又采用在客户端中逐字段复制的方法进行拷贝操作的话,将不可避免的造成客户端代码繁杂冗长,而且也无法对类中的私有成员进行复制,而如果让需要具备拷贝功能的类实现Cloneable接口,并重写clone()方法,就可以通过调用clone()方法的方式简洁地实现实例拷贝功能。
深拷贝(深复制)和浅拷贝(浅复制)是两个比较通用的概念,尤其在C++语言中,若不弄懂,则会在delete的时候出问题,但是我们在这幸好用的是Java。虽然Java自动管理对象的回收,但对于深拷贝(深复制)和浅拷贝(浅复制),我们还是要给予足够的重视,因为有时这两个概念往往会给我们带来不小的困惑。
-
浅拷贝是指拷贝对象时仅仅拷贝对象本身(包括对象中的基本变量),而不拷贝对象包含的引用指向的对象。深拷贝不仅拷贝对象本身,而且拷贝对象包含的引用指向的所有对象。举例来说更加清楚:对象 A1 中包含对 B1 的引用, B1 中包含对 C1 的引用。浅拷贝 A1 得到 A2 , A2 中依然包含对 B1 的引用, B1 中依然包含对 C1 的引用。
-
深拷贝则是对浅拷贝的递归,深拷贝 A1 得到 A2 , A2 中包含对 B2 ( B1 的 copy )的引用, B2 中包含对 C2 ( C1 的 copy )的引用。
若不对clone()方法进行改写,则调用此方法得到的对象即为浅拷贝
@Data
public static class Teacher implements Cloneable {
String username;
@Override
protected Teacher clone() throws CloneNotSupportedException {
return (Teacher) super.clone();
}
}
@Data
public static class School implements Cloneable{
String name;
Teacher teacher;
@Override
protected School clone() throws CloneNotSupportedException {
School s = null;
s = (School)super.clone();
s.teacher = (Teacher) teacher.clone();
return s;
}
}
@Test
public void test_11() throws CloneNotSupportedException {
Teacher teacher = new Teacher();
teacher.setUsername("1111");
School school = new School();
school.setName("111");
school.setTeacher(teacher);
log.info(JSON.toJSONString(school));
School school1 = school.clone();
school1.setName("222");
school1.getTeacher().setUsername("2222");
log.info(JSON.toJSONString(school));
log.info(JSON.toJSONString(school1));
}
运行结果:
2022-01-15 15:10:39.812 INFO 2815 --- [ main] com.kolaer.cms.CmsApplicationTests : {"name":"111","teacher":{"username":"1111"}}
2022-01-15 15:10:39.812 INFO 2815 --- [ main] com.kolaer.cms.CmsApplicationTests : {"name":"111","teacher":{"username":"1111"}}
2022-01-15 15:10:39.812 INFO 2815 --- [ main] com.kolaer.cms.CmsApplicationTests : {"name":"222","teacher":{"username":"2222"}}