往期回顾,专栏一览
🍉 JavaSE🍋 AWT🍑 数据结构🍅 C1进阶之路🍒 每日一练🌽 代码报错🍈 活动
🍹欢迎各路大佬来到 Nick 主页指点
☀️本期文章将学习 [JavaSE] Clonable 克隆****,我是博主Nick。✨
✨我的博客主页:Nick_Bears** 🌹꧔ꦿ**
🌹꧔ꦿ博文内容如对您有所帮助,还请给个点赞 + 关注 + 收藏✨
🔴 Clonable
**🔵 **对象创建
- new
- 克隆方法
class Person{ public String name; public Money money = new Money(); public void play() { System.out.println("敲代码"); } @Override public String toString() { return "Person{" + "name=" + name + '}'; } public class Demo { public static void main(String[] args) { Person person = new Person(); Person person1 = person.clone(); } }
**🔸 **我们发现 clone() 是爆红的,我们查看 clone() 的源码试试
**🔸 **于是改成
Person person1 = (Person)person.clone();
**🔸 **恶心的是仍然报错!!!通过学习,我们知道一个对象实现 clone 说明该对象是可克隆的!于是在被克隆类上实现 Cloneable 接口。
class Person implements Cloneable{ public int age; public void play(){ System.out.println("玩!"); } @Override public String toString() { return "Person{" + "age=" + age + '}'; } //快捷键:Ctrl + O @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } }
**🔸 **我们发现 clone() 还是爆红的,那么我们抛一下异常
public class Demo { public static void main(String[] args) throws CloneNotSupportedException { Person person = new Person(); //并且抛出异常即可 Person person1 = (Person) person.clone(); } }
🔵 调用方法
思考:person 默认继承** Object**,为什么通过引用不能调用克隆方法?
答:可以调用,只是 clone 比较特殊,只是我们必须要重写。
@Override protected Object clone() throws CloneNotSupportedException { return super.clone(); }
**🔸 **我们已经调用了 clone() 方法,他会帮我们做什么事情?产生一个副本!
**🔵 **小结:一个对象如何被克隆?
- 必须实现 Cloneable 接口
- 重写** Object** 的 clone() 方法
- 调用方法抛异常
**💠 **输出克隆的对象
public class Demo { public static void main(String[] args) throws CloneNotSupportedException { Person person = new Person(); person.age = 99; Person person1 = (Person) person.clone(); System.out.println(person1); } } //输出 Person{age=99}
**💠 **修改克隆对象的值,查看克隆值和原来的值
public class Demo { public static void main(String[] args) throws CloneNotSupportedException { Person person = new Person(); person.age = 99; Person person1 = (Person) person.clone(); System.out.println(person1); System.out.println("===================="); person1.age=199; System.out.println(person); System.out.println(person1); } } //输出 Person{age=99} ==================== Person{age=99} Person{age=199}
答:决定是 深拷贝 还是 浅拷贝 不是某一个方法的使用,或者对应哪种数据类型,而是代码的实现,就是你的代码是如何写的,处理过程如何!我只能说在这种情况下这是深拷贝。
🔵 面试问题
- 思考:你知道Clonable接口吗?
- 思考:为啥这接口是个空接口?
- 思考:有啥作用?
答:空接口->标志接口->代表当前类可以被克隆。
**🔵 **代码升华!浅拷贝?
**🔹 **我给 Person 新增了一个 Money 属性
class Money{ public double m = 13.14; } class Person implements Cloneable{ public int age; public Money money = new Money(); public void play(){ System.out.println("玩!"); } @Override public String toString() { return "Person{" + "age=" + age + '}'; } @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } } public static void main(String[] args) throws CloneNotSupportedException { Person person = new Person(); Person person1 = (Person) person.clone(); }
**🔹 **我们通过图推测下面的代码运行都是13.14
public static void main(String[] args) throws CloneNotSupportedException { Person person = new Person(); Person person1 = (Person) person.clone(); System.out.println(person.money.m); System.out.println(person1.money.m); System.out.println("================"); } //结果 13.14 13.14 ================
**🔹 **那么我们现在来改掉一个值,可想而知都是同一个引用
public static void main(String[] args) throws CloneNotSupportedException { Person person = new Person(); Person person1 = (Person) person.clone(); System.out.println(person.money.m); System.out.println(person1.money.m); System.out.println("================"); person1.money.m = 1314; System.out.println(person.money.m); System.out.println(person1.money.m); } //结果 13.14 13.14 ================ 1314.0 1314.0
**🔹 **对于目前情况来说,这是一个浅拷贝,那么我们如何实现深拷贝呢?我们是不是应该也把 Money 复制一份呢?
**🔵 **深拷贝实现!
**🔹 **我们在上面代码的基础上添加一些代码,对 Money 也连接克隆接口,并且重写
class Money implements Cloneable { public double m = 13.14; @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } }
**🔹 **这样以后我们就能对 Money 也拷贝一份(在 Person 的方法中)
@Override protected Object clone() throws CloneNotSupportedException { Person tmp = (Person)super.clone(); //把钱也拷贝一份 tmp.money = (Money)this.money.clone(); //return super.clone(); return tmp; }
![](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)
**🔹 **此时我们再次测试刚刚的方法
public static void main(String[] args) throws CloneNotSupportedException { Person person = new Person(); Person person1 = (Person) person.clone(); System.out.println(person.money.m); System.out.println(person1.money.m); System.out.println("================"); person1.money.m = 1314; System.out.println(person.money.m); System.out.println(person1.money.m); } //运行结果 13.14 13.14 ================ 13.14 1314.0
**🔵 **代码一览
package 接口.常用接口.Clonable; /** * 1、面试问题: * 你知道Cloneable接口吗? * 为啥这个接口是一个空接口? * 有啥作用? 空接口->标志接口->代表当前这个类是可以被克隆的 * 2、创建对象的方式 * 1.new * 2.克隆方法 */ class Money implements Cloneable{ public double m = 10000; @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } } class Person implements Cloneable { public String name; public Money money = new Money(); public void play() { System.out.println("玩王者"); } @Override public String toString() { return "Person{" + "name=" + name + '}'; } /** * * tmp.money = (Money) this.money.clone(); 我把克隆出来的tmp中的money也给克隆一份 * @return 我以前返回的就是一个tmp,现在是已经克隆好 money 的 tmp; * @throws CloneNotSupportedException */ @Override protected Object clone() throws CloneNotSupportedException { Person tmp =(Person)super.clone(); tmp.money = (Money) this.money.clone(); // return super.clone(); return tmp; } } public class Demo { /** * 克隆 * 特殊点:想要调用clone,必须先重写(尽管都是继承于Object下的) * * 决定深拷贝还是浅拷贝取决于代码的实现,而不是某一个方法 * @param args */ public static void main1(String[] args) throws CloneNotSupportedException { Person person = new Person(); person.name = "Nick"; Person person1 = (Person) person.clone(); System.out.println(person1); System.out.println("============================"); person1.name = "Nicks"; System.out.println(person1); System.out.println(person); //执行结果 // Person{name=Nick} //============================ // Person{name=Nicks} // Person{name=Nick} } /** * 浅克隆 * 通过此方法运行流程来看,这个浅克隆 * * 思考?如何实现深拷贝呢? * 我们通过接口来拷贝对象,那么我们重写接口试试... * */ public static void main(String[] args) throws CloneNotSupportedException { Person person = new Person(); Person person1 = (Person) person.clone(); System.out.println(person.money.m); System.out.println(person1.money.m); System.out.println("==============================="); person1.money.m = 999999; System.out.println(person.money.m); System.out.println(person1.money.m); //运行结果(重写接口前) // 10000.0 // 10000.0 // ============================== // 999999.0 // 999999.0 } //运行结果(重写接口后) // 10000.0 // 10000.0 // =============================== // 10000.0 // 999999.0 }
版权归原作者 Nick_Bears 所有, 如有侵权,请联系我们删除。