一、浅复制和深复制概念

浅复制(浅克隆): 被复制对象的所有变量都含有与原来对象相同的值,而所有的对其他对象的引用仍然指向原来的对象。换言之,浅复制仅仅复制所考虑的对象,而不是复制它所引用的对象。

深复制(深克隆): 被复制对象的所有变量都含有与原来对象相同的值,除去那些引用其他对象的变量。那些引用其他对象的变量将指向被复制过的新对象, 而不再试原有的那些被引用的对象。换言之,深复制把复制的对象所应用的对象都复制了一遍。

二、Java的Clone()方法 【定义在Object类中】

clone方法将对象复制一份并返回给调用者。

一般而言,clone()  方法满足:

1、对任何对象x,都有x.clone() != x

克隆对象与原对象不是一个对象

2、对任何的对象x,都有

x.clone().getClass() == x.getClass()

克隆对象与原对象的类型一样

3、如果对象x的equals()方法定义恰当,那么x.clone().equals(x)应该成立

二、浅复制Demo

  1. public class CloneTest1 {
  2.  
  3. public static void main(String[] args) throws CloneNotSupportedException {
  4. Student student = new Student();
  5. student.setAge(20);
  6. student.setName("Larry");
  7.  
  8. Student student2 = (Student)student.clone();
  9. System.out.println(student2.getAge());
  10. System.out.println(student2.getName());
  11.  
  12. System.out.println("-----------------------");
  13.  
  14. student2.setName("Nick");
  15. System.out.println(student.getName());
  16. System.out.println(student2.getName());
  17.  
  18. }
  19. }
  20.  
  21. class Student implements Cloneable{
  22. private int age;
  23. private String name;
  24. public int getAge() {
  25. return age;
  26. }
  27. public void setAge(int age) {
  28. this.age = age;
  29. }
  30. public String getName() {
  31. return name;
  32. }
  33. public void setName(String name) {
  34. this.name = name;
  35. }
  36.  
  37. @Override
  38. public Object clone() throws CloneNotSupportedException {
  39. Object object = super.clone();
  40. return object;
  41. }
  42. }

打印结果

20
zhangsan
-----------------------
zhangsan
Lisi

  1. student2.setName("Nick"); 执行后,student2name赋予新的值,指向新的空间。如下图

  1. 三、深复制
    以下代码还是浅复制
  1. public class CloneTest2 {
  2.  
  3. public static void main(String[] args) throws CloneNotSupportedException {
  4.  
  5. Teacher teacher = new Teacher();
  6. teacher.setAge(40);
  7. teacher.setName("Teacher zhang");
  8.  
  9. Student2 s1 = new Student2();
  10. s1.setAge(20);
  11. s1.setName("zhangsan");
  12. s1.setTeacher(teacher);
  13.  
  14. Student2 s2 = (Student2)s1.clone();
  15. System.out.println(s2.getAge());
  16. System.out.println(s2.getName());
  17.  
  18. teacher.setName("Teacher Li");
  19.  
  20. System.out.println(s2.getTeacher().getAge());
  21. System.out.println(s2.getTeacher().getName());
  22.  
  23. }
  24. }
  25.  
  26. class Teacher {
  27. private int age;
  28. private String name;
  29.  
  30. public int getAge() {
  31. return age;
  32. }
  33. public void setAge(int age) {
  34. this.age = age;
  35. }
  36. public String getName() {
  37. return name;
  38. }
  39. public void setName(String name) {
  40. this.name = name;
  41. }
  42.  
  43. }
  44.  
  45. class Student2 implements Cloneable{
  46. private int age;
  47. private String name;
  48.  
  49. private Teacher teacher;
  50.  
  51. public int getAge() {
  52. return age;
  53. }
  54. public void setAge(int age) {
  55. this.age = age;
  56. }
  57. public String getName() {
  58. return name;
  59. }
  60. public void setName(String name) {
  61. this.name = name;
  62. }
  63.  
  64. public Teacher getTeacher() {
  65. return teacher;
  66. }
  67. public void setTeacher(Teacher teacher) {
  68. this.teacher = teacher;
  69. }
  70. @Override
  71. public Object clone() throws CloneNotSupportedException {
  72. Object object = super.clone();
  73. return object;
  74. }
  75. }

修改成深复制

Teacher也实现Clone方法

然后改写Student的Clone方法

clone Student的时候,修改Teacher。

修改后的完整代码:

  1. public class CloneTest2 {
  2.  
  3. public static void main(String[] args) throws CloneNotSupportedException {
  4.  
  5. Teacher teacher = new Teacher();
  6. teacher.setAge(40);
  7. teacher.setName("Teacher zhang");
  8.  
  9. Student2 s1 = new Student2();
  10. s1.setAge(20);
  11. s1.setName("zhangsan");
  12. s1.setTeacher(teacher);
  13.  
  14. Student2 s2 = (Student2)s1.clone();
  15. System.out.println(s2.getAge());
  16. System.out.println(s2.getName());
  17.  
  18. teacher.setName("Teacher Li");
  19.  
  20. System.out.println(s2.getTeacher().getAge());
  21. System.out.println(s2.getTeacher().getName());
  22.  
  23. }
  24. }
  25.  
  26. class Teacher implements Cloneable{
  27. private int age;
  28. private String name;
  29.  
  30. public int getAge() {
  31. return age;
  32. }
  33. public void setAge(int age) {
  34. this.age = age;
  35. }
  36. public String getName() {
  37. return name;
  38. }
  39. public void setName(String name) {
  40. this.name = name;
  41. }
  42.  
  43. @Override
  44. public Object clone() throws CloneNotSupportedException {
  45.  
  46. return super.clone();
  47. }
  48.  
  49. }
  50.  
  51. class Student2 implements Cloneable{
  52. private int age;
  53. private String name;
  54.  
  55. private Teacher teacher;
  56.  
  57. public int getAge() {
  58. return age;
  59. }
  60. public void setAge(int age) {
  61. this.age = age;
  62. }
  63. public String getName() {
  64. return name;
  65. }
  66. public void setName(String name) {
  67. this.name = name;
  68. }
  69.  
  70. public Teacher getTeacher() {
  71. return teacher;
  72. }
  73. public void setTeacher(Teacher teacher) {
  74. this.teacher = teacher;
  75. }
  76. @Override
  77. public Object clone() throws CloneNotSupportedException {
  78. Student2 student2 = (Student2)super.clone();
  79. student2.setTeacher((Teacher)student2.getTeacher().clone());
  80. return student2;
  81. }
  82. }

  

五、利用序列化来做深复制(最简单也是最多的一种方式)

1、使用Clone方法实现深复制存在的缺点: 存在多个引用的成员变量,将做多次处理。

如上图做了一次处理,如果有多个应用,将做多次处理。

2、序列化/反序列化

把对象写到流里的过程是序列化(Serilization)过程,而把对象从流中读取出来的过程则叫饭序列化(Deserialization)过程。应当指出的是,写在流里的是对象的一个拷贝,而原对象仍然存在于JVM里面

1)在Java语言里深复制一个对象,常常可以先使对象实现Serializable接口,然后把对象(实际上只是对象的一个拷贝)写到一个流里,再从流里读出来,便可以重建对象。

2)这样做的前提示对象以及对象内部所有引用到的对象都是可串行化的,否则,就需要仔细考察那些不可串行化的对象是否设成transient,从而将之排除在复制过程之外。

3)Code

  1. public class CloneTest3 {
  2.  
  3. public static void main(String[] args) throws Exception {
  4.  
  5. Teacher3 teacher = new Teacher3();
  6. teacher.setAge(40);
  7. teacher.setName("Teacher zhang");
  8.  
  9. Student3 s1 = new Student3();
  10. s1.setAge(20);
  11. s1.setName("zhangsan");
  12. s1.setTeacher(teacher);
  13.  
  14. Student3 s2 = (Student3)s1.deepCopy();
  15. System.out.println(s2.getAge());
  16. System.out.println(s2.getName());
  17. System.out.println("-------------");
  18.  
  19. System.out.println(s2.getTeacher().getAge());
  20. System.out.println(s2.getTeacher().getName());
  21.  
  22. s2.getTeacher().setAge(50);
  23. s2.getTeacher().setName("Teacher Li");
  24.  
  25. System.out.println(s1.getTeacher().getAge());
  26. System.out.println(s1.getTeacher().getName());
  27.  
  28. }
  29. }
  30.  
  31. class Teacher3 implements Serializable{
  32.  
  33. //private static final long serialVersionUID = 675697793444541314L;
  34. private int age;
  35. private String name;
  36.  
  37. public int getAge() {
  38. return age;
  39. }
  40. public void setAge(int age) {
  41. this.age = age;
  42. }
  43. public String getName() {
  44. return name;
  45. }
  46. public void setName(String name) {
  47. this.name = name;
  48. }
  49.  
  50. }
  51.  
  52. class Student3 implements Serializable{
  53.  
  54. //private static final long serialVersionUID = -7008294898863009451L;
  55. private int age;
  56. private String name;
  57.  
  58. private Teacher3 teacher;
  59.  
  60. public int getAge() {
  61. return age;
  62. }
  63. public void setAge(int age) {
  64. this.age = age;
  65. }
  66. public String getName() {
  67. return name;
  68. }
  69. public void setName(String name) {
  70. this.name = name;
  71. }
  72.  
  73. public Teacher3 getTeacher() {
  74. return teacher;
  75. }
  76. public void setTeacher(Teacher3 teacher) {
  77. this.teacher = teacher;
  78. }
  79.  
  80. public Object deepCopy() throws Exception {
  81. //将对象写入流
  82. ByteArrayOutputStream bos = new ByteArrayOutputStream();
  83. ObjectOutputStream oos = new ObjectOutputStream(bos);
  84. oos.writeObject(this);
  85. //从流中读取对象
  86. ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
  87. ObjectInputStream ois = new ObjectInputStream(bis);
  88. return ois.readObject();
  89. }
  90.  
  91. }

  打印结果:

  1. 20
  2. zhangsan
  3. -------------
  4. 40
  5. Teacher zhang
  6. 40
  7. Teacher zhang

  

六、关于实现Seriallizable接口的类中的serialVersionUID问题

如果你的对象序列化后存在硬盘上面后,可是后来你更改了类的field(增加或减少或改名),当你反序列化时,就会出现Execption的,这样就会造成不兼容性的问题。

但当serialVersionUID相同时,它就会将不一样的field以type的缺省值Deserialize,这样可以避开不兼容的问题。

深拷贝(deep clone)与浅拷贝(shallow clone)的更多相关文章

  1. 深拷贝(deep clone)与浅拷贝(shallow clone)

    深拷贝(deep clone)与浅拷贝(shallow clone) 浅复制(浅克隆):被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象.换言之,浅复制仅仅复 ...

  2. java的clone()、浅拷贝与深拷贝

    clone()方法是Object的native方法.protected native Object clone() throws CloneNotSupportedException;  声明为pro ...

  3. Java:浅克隆(shallow clone)与深克隆(deep clone)

    Summary 浅克隆与深克隆对于JavaSE来说,是个难度系数比较低的概念,但不应该轻视它. 假设一个场景:对于某个list,代码里并没有任何对其的直接操作,但里面的元素的属性却被改变了,这可能就涉 ...

  4. 由Python的浅拷贝(shallow copy)和深拷贝(deep copy)引发的思考

    首先查看拷贝模块(copy)发现: >>> help(copy)Help on module copy:NAME    copy - Generic (shallow and dee ...

  5. copy&mutableCopy 浅拷贝(shallow copy)深拷贝 (deep copy)

    写在前面 其实看了这么多,总结一个结论: 拷贝的初衷的目的就是为了:修改原来的对象不能影响到拷贝出来得对象 && 修改拷贝出来的对象也不能影响到原来的对象 所以,如果原来对象就是imm ...

  6. shallow clone

    shallow clone 浅克隆经常在一些大型仓库中很有用——不用花费大量时间去clone一个完整的仓库,仅仅checkout出来某个分支(如master)的最新N次递交: git clone -- ...

  7. Java中的深拷贝(深复制)和浅拷贝(浅复制)

    深拷贝(深复制)和浅拷贝(浅复制)是两个比较通用的概念,尤其在C++语言中,若不弄懂,则会在delete的时候出问题,但是我们在这幸好用的是Java.虽然java自动管理对象的回收,但对于深拷贝(深复 ...

  8. git clone 和 download 不一样,能用git clone 就用git clone,download的代码,经常出现安装bug

    git clone 和 download 不一样,能用git clone 就用git clone,download的代码,经常出现安装bug

  9. 浅谈浅克隆(shallow clone)和 深克隆(deep clone)

    区别就在于是否对对象中的引用变量所指向的对象进行拷贝. 1.浅克隆/浅复制/浅拷贝 浅拷贝是指在拷贝对象时,对于基本数据类型的变量会重新复制一份,而对于引用类型的变量只是对引用进行拷贝,没有对引用指向 ...

随机推荐

  1. 三步操作gitHub汉化插件安装--谷歌浏览器

    如果本文对你有用,请爱心点个赞,提高排名,帮助更多的人.谢谢大家!❤ 如果解决不了,可以在文末进群交流. 一个好用基于chrome的插件,用来汉化gitHub,大致效果图如下: 步骤一: 首先下载谷歌 ...

  2. mysql8.x 新版本jdbc连接方式

    旧版本,MySQL Connector/J 5.x 版本的连接方式:url = jdbc:mysql://localhost:3306/thrcloud_db01?useUnicode=true&am ...

  3. Linux正则表达式,grep总结,sed用法

    原文: 1.sed   流编辑器,实现对文字的增删改替换查(过滤.取行),能同时处理多个文件多行的内容,可以不对原文件改动,把整个文件 输入到屏幕,可以把只匹配到模式的内容输入到屏幕上.还可以对原文件 ...

  4. [daily] ssh通过私钥导出公钥

    在使用key方式登录ssh服务的时候,我们知道ssh key是使用公钥ssh-keygen工具生成的. 有时候,我们只保存了私钥,但是并没有保存公钥.这个时候,可以使用如下方法,   从私钥中将公钥导 ...

  5. LAMP环境搭建基本步骤

    LAMP环境搭建基本步骤 参考链接https://yq.aliyun.com/articles/106387 apache性能优化.配置https://my.oschina.net/lockupme/ ...

  6. nginx_status

    server { listen ; server_name blog.oldboy.com; root /code/wordpress; index index.php index.html; loc ...

  7. Java 十大排序算法

    目录: 1.冒泡排序(Bubble Sort) 2.选择排序(Selection Sort) 3.插入排序(Insertion Sort) 4.希尔排序(Shell Sort) 5.归并排序(Merg ...

  8. 用js刷剑指offer(两个链表的第一个公共结点)

    题目描述 输入两个链表,找出它们的第一个公共结点. 牛客网链接 js代码 /*function ListNode(x){ this.val = x; this.next = null; }*/ fun ...

  9. (java)selenium webdriver学习--打开新窗口,并判断新窗口是否与目标窗口一致

    描述:selenium webdriver学习--打开新窗口,并判断新窗口是否与目标窗口一致,若一致则切换到该窗口并获取标题 跳出if判断,获取父级标题,并关闭 HTML标签不太明显时,可以用路径表示 ...

  10. .NET 中String 和StringBuilder 以及他们的区别

    stirng对象是不可变的,每次使用String类的方法进行运算时(赋值.拼接),都会在内存中生成新的字符串对象,这就要为新对象分配新的内存空间. StringBuilder 实例的 int Capa ...