0


[JavaSE] Clonable(深克隆,浅克隆)

往期回顾,专栏一览

🍉 JavaSE🍋 AWT🍑 数据结构🍅 C1进阶之路🍒 每日一练🌽 代码报错🍈 活动

🍹欢迎各路大佬来到 Nick 主页指点

☀️本期文章将学习 [JavaSE] Clonable 克隆****,我是博主Nick。✨

✨我的博客主页:Nick_Bears** 🌹꧔ꦿ**

🌹꧔ꦿ博文内容如对您有所帮助,还请给个点赞 + 关注 + 收藏✨

🔴 Clonable

**🔵 **对象创建


  1. new
  2. 克隆方法
  1. class Person{
  2. public String name;
  3. public Money money = new Money();
  4. public void play() {
  5. System.out.println("敲代码");
  6. }
  7. @Override
  8. public String toString() {
  9. return "Person{" +
  10. "name=" + name +
  11. '}';
  12. }
  13. public class Demo {
  14. public static void main(String[] args) {
  15. Person person = new Person();
  16. Person person1 = person.clone();
  17. }
  18. }

**🔸 **我们发现 clone() 是爆红的,我们查看 clone() 的源码试试

**🔸 **于是改成

  1. Person person1 = (Person)person.clone();

**🔸 **恶心的是仍然报错!!!通过学习,我们知道一个对象实现 clone 说明该对象是可克隆的!于是在被克隆类上实现 Cloneable 接口。

  1. class Person implements Cloneable{
  2. public int age;
  3. public void play(){
  4. System.out.println("玩!");
  5. }
  6. @Override
  7. public String toString() {
  8. return "Person{" +
  9. "age=" + age +
  10. '}';
  11. }
  12. //快捷键:Ctrl + O
  13. @Override
  14. protected Object clone() throws CloneNotSupportedException {
  15. return super.clone();
  16. }
  17. }

**🔸 **我们发现 clone() 还是爆红的,那么我们抛一下异常

  1. public class Demo {
  2. public static void main(String[] args) throws CloneNotSupportedException {
  3. Person person = new Person();
  4. //并且抛出异常即可
  5. Person person1 = (Person) person.clone();
  6. }
  7. }

🔵 调用方法

思考:person 默认继承** Object**,为什么通过引用不能调用克隆方法?

答:可以调用,只是 clone 比较特殊,只是我们必须要重写。

  1. @Override
  2. protected Object clone() throws CloneNotSupportedException {
  3. return super.clone();
  4. }

**🔸 **我们已经调用了 clone() 方法,他会帮我们做什么事情?产生一个副本!

**🔵 **小结:一个对象如何被克隆?

  • 必须实现 Cloneable 接口
  • 重写** Object** 的 clone() 方法
  • 调用方法抛异常

**💠 **输出克隆的对象

  1. public class Demo {
  2. public static void main(String[] args) throws CloneNotSupportedException {
  3. Person person = new Person();
  4. person.age = 99;
  5. Person person1 = (Person) person.clone();
  6. System.out.println(person1);
  7. }
  8. }
  9. //输出
  10. Person{age=99}

**💠 **修改克隆对象的值,查看克隆值和原来的值

  1. public class Demo {
  2. public static void main(String[] args) throws CloneNotSupportedException {
  3. Person person = new Person();
  4. person.age = 99;
  5. Person person1 = (Person) person.clone();
  6. System.out.println(person1);
  7. System.out.println("====================");
  8. person1.age=199;
  9. System.out.println(person);
  10. System.out.println(person1);
  11. }
  12. }
  13. //输出
  14. Person{age=99}
  15. ====================
  16. Person{age=99}
  17. Person{age=199}

答:决定是 深拷贝 还是 浅拷贝 不是某一个方法的使用,或者对应哪种数据类型,而是代码的实现,就是你的代码是如何写的,处理过程如何!我只能说在这种情况下这是深拷贝。

🔵 面试问题

  • 思考:你知道Clonable接口吗?
  • 思考:为啥这接口是个空接口?
  • 思考:有啥作用?

答:空接口->标志接口->代表当前类可以被克隆。

**🔵 **代码升华!浅拷贝?

**🔹 **我给 Person 新增了一个 Money 属性

  1. class Money{
  2. public double m = 13.14;
  3. }
  4. class Person implements Cloneable{
  5. public int age;
  6. public Money money = new Money();
  7. public void play(){
  8. System.out.println("玩!");
  9. }
  10. @Override
  11. public String toString() {
  12. return "Person{" +
  13. "age=" + age +
  14. '}';
  15. }
  16. @Override
  17. protected Object clone() throws CloneNotSupportedException {
  18. return super.clone();
  19. }
  20. }
  21. public static void main(String[] args) throws CloneNotSupportedException {
  22. Person person = new Person();
  23. Person person1 = (Person) person.clone();
  24. }

**🔹 **我们通过图推测下面的代码运行都是13.14

  1. public static void main(String[] args) throws CloneNotSupportedException {
  2. Person person = new Person();
  3. Person person1 = (Person) person.clone();
  4. System.out.println(person.money.m);
  5. System.out.println(person1.money.m);
  6. System.out.println("================");
  7. }
  8. //结果
  9. 13.14
  10. 13.14
  11. ================

**🔹 **那么我们现在来改掉一个值,可想而知都是同一个引用

  1. public static void main(String[] args) throws CloneNotSupportedException {
  2. Person person = new Person();
  3. Person person1 = (Person) person.clone();
  4. System.out.println(person.money.m);
  5. System.out.println(person1.money.m);
  6. System.out.println("================");
  7. person1.money.m = 1314;
  8. System.out.println(person.money.m);
  9. System.out.println(person1.money.m);
  10. }
  11. //结果
  12. 13.14
  13. 13.14
  14. ================
  15. 1314.0
  16. 1314.0

**🔹 **对于目前情况来说,这是一个浅拷贝,那么我们如何实现深拷贝呢?我们是不是应该也把 Money 复制一份呢?

**🔵 **深拷贝实现!

**🔹 **我们在上面代码的基础上添加一些代码,对 Money 也连接克隆接口,并且重写

  1. class Money implements Cloneable {
  2. public double m = 13.14;
  3. @Override
  4. protected Object clone() throws CloneNotSupportedException {
  5. return super.clone();
  6. }
  7. }

**🔹 **这样以后我们就能对 Money 也拷贝一份(在 Person 的方法中)

  1. @Override
  2. protected Object clone() throws CloneNotSupportedException {
  3. Person tmp = (Person)super.clone();
  4. //把钱也拷贝一份
  5. tmp.money = (Money)this.money.clone();
  6. //return super.clone();
  7. return tmp;
  8. }
  1. ![](https://img-blog.csdnimg.cn/69a31b3ec0164621a6bf6025ed404972.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBATmlja19CZWFycw==,size_20,color_FFFFFF,t_70,g_se,x_16)

**🔹 **此时我们再次测试刚刚的方法

  1. public static void main(String[] args) throws CloneNotSupportedException {
  2. Person person = new Person();
  3. Person person1 = (Person) person.clone();
  4. System.out.println(person.money.m);
  5. System.out.println(person1.money.m);
  6. System.out.println("================");
  7. person1.money.m = 1314;
  8. System.out.println(person.money.m);
  9. System.out.println(person1.money.m);
  10. }
  11. //运行结果
  12. 13.14
  13. 13.14
  14. ================
  15. 13.14
  16. 1314.0

**🔵 **代码一览

  1. package 接口.常用接口.Clonable;
  2. /**
  3. * 1、面试问题:
  4. * 你知道Cloneable接口吗?
  5. * 为啥这个接口是一个空接口?
  6. * 有啥作用? 空接口->标志接口->代表当前这个类是可以被克隆的
  7. * 2、创建对象的方式
  8. * 1.new
  9. * 2.克隆方法
  10. */
  11. class Money implements Cloneable{
  12. public double m = 10000;
  13. @Override
  14. protected Object clone() throws CloneNotSupportedException {
  15. return super.clone();
  16. }
  17. }
  18. class Person implements Cloneable {
  19. public String name;
  20. public Money money = new Money();
  21. public void play() {
  22. System.out.println("玩王者");
  23. }
  24. @Override
  25. public String toString() {
  26. return "Person{" +
  27. "name=" + name +
  28. '}';
  29. }
  30. /**
  31. *
  32. * tmp.money = (Money) this.money.clone(); 我把克隆出来的tmp中的money也给克隆一份
  33. * @return 我以前返回的就是一个tmp,现在是已经克隆好 money 的 tmp;
  34. * @throws CloneNotSupportedException
  35. */
  36. @Override
  37. protected Object clone() throws CloneNotSupportedException {
  38. Person tmp =(Person)super.clone();
  39. tmp.money = (Money) this.money.clone();
  40. // return super.clone();
  41. return tmp;
  42. }
  43. }
  44. public class Demo {
  45. /**
  46. * 克隆
  47. * 特殊点:想要调用clone,必须先重写(尽管都是继承于Object下的)
  48. *
  49. * 决定深拷贝还是浅拷贝取决于代码的实现,而不是某一个方法
  50. * @param args
  51. */
  52. public static void main1(String[] args) throws CloneNotSupportedException {
  53. Person person = new Person();
  54. person.name = "Nick";
  55. Person person1 = (Person) person.clone();
  56. System.out.println(person1);
  57. System.out.println("============================");
  58. person1.name = "Nicks";
  59. System.out.println(person1);
  60. System.out.println(person);
  61. //执行结果
  62. // Person{name=Nick}
  63. //============================
  64. // Person{name=Nicks}
  65. // Person{name=Nick}
  66. }
  67. /**
  68. * 浅克隆
  69. * 通过此方法运行流程来看,这个浅克隆
  70. *
  71. * 思考?如何实现深拷贝呢?
  72. * 我们通过接口来拷贝对象,那么我们重写接口试试...
  73. *
  74. */
  75. public static void main(String[] args) throws CloneNotSupportedException {
  76. Person person = new Person();
  77. Person person1 = (Person) person.clone();
  78. System.out.println(person.money.m);
  79. System.out.println(person1.money.m);
  80. System.out.println("===============================");
  81. person1.money.m = 999999;
  82. System.out.println(person.money.m);
  83. System.out.println(person1.money.m);
  84. //运行结果(重写接口前)
  85. // 10000.0
  86. // 10000.0
  87. // ==============================
  88. // 999999.0
  89. // 999999.0
  90. }
  91. //运行结果(重写接口后)
  92. // 10000.0
  93. // 10000.0
  94. // ===============================
  95. // 10000.0
  96. // 999999.0
  97. }

标签: 克隆 接口 java

本文转载自: https://blog.csdn.net/weixin_50369395/article/details/124218428
版权归原作者 Nick_Bears 所有, 如有侵权,请联系我们删除。

“[JavaSE] Clonable(深克隆,浅克隆)”的评论:

还没有评论