Android应用开发之Android冷知识——Java中的克隆
凌雪 2018-09-21 来源 :网络 阅读 594 评论 0

摘要:本文将带你了解Android应用开发之Android冷知识——Java中的克隆,希望本文对大家学Android有所帮助。

本文将带你了解Android应用开发之Android冷知识——Java中的克隆,希望本文对大家学Android有所帮助。


对象的创建
    在Android中,对象的创建分为两种形式,一种是使用new操作符创建对象,另一种是调用clone方法复制对象。这两个操作在使用上有以下的区别:
    使用new操作符创建对象:对new的对象分配内存,调用其构造方法,并将创建好的对象引用发布到外部 调用clone方法复制对象:对clone的对象分配内存,对新分配的内存域使用原对象进行填充,并将clone的对象引用发布到外部
    克隆的使用
    在对象中可以使用clone(),必须实现Cloneable接口,复写clone方法,外部才可以调用clone()
    ?12345678910public class Person implements Cloneable{  public   String name; public int age;  @Override protected Object   clone() throws CloneNotSupportedException {  return   super.clone(); }}
    复制对象和复制引用
    一、复制对象
    Person p1 = new Person();Person p2 =   p1; Log.e("TAG", p1.toString());Log.e("TAG",   p2.toString());
通过输出的结果看出,两个对象的地址是相同的,所以这两个对象是同一个对象,这种现象叫做对象的复制
com.hensen.fashionsource.Person@a6ea782com.hensen.fashionsource.Person@a6ea782
二、复制引用
try { Person p1 = new Person(); Person   p2 = (Person) p1.clone();  Log.e("TAG",   p1.toString()); Log.e("TAG", p2.toString());} catch   (CloneNotSupportedException e) { e.printStackTrace();}
通过输出的结果看出,两个对象的地址不相同,所以这两个对象是不同对象,这种现象叫做引用的复制
com.hensen.fashionsource.Person@38b31e93com.hensen.fashionsource.Person@3046fed0
浅拷贝和深拷贝
    使用clone()的过程中,clone会遇到浅拷贝和深拷贝的问题,下面是浅拷贝和深拷贝的概念介绍:
      浅拷贝:将对象中的所有字段复制到新的对象中。其中,基本数据类型的值被复制到对象中后,在对象中的修改不会影响到源对象对应的值。而引用类型的值被复制到对象中还是引用类型的引用,而不是引用的对象,在对象中对引用类型的字段值做修改会影响到源对象本身。简单的说,只拷贝基本数据类型,引用类型不会被拷贝。 深拷贝:将对象中的所有字段复制到新的对象中。不过,无论是对象的基本数据类型,还是引用类型,都会被重新创建并赋值,对于新对象的修改,不会影响到源对象本身。简单的说,拷贝出完全相同的对象,对新对象的修改和源对象没有任何关系。
clone()属于浅拷贝,但是也可以将clone()方法转换成深拷贝的处理,下面开始介绍
    一、String类型的特殊性
    由于clone()属于浅拷贝,那么在上面的例子中,按理说,Person对象的name字段,String类型不是基本数据类型,且String没有实现Cloneable接口,在这里调用clone()仅仅是复制了String引用,那么克隆之后的对象修改name字段的值会不会将原来的值也改变了?下面我们通过例子验证
try { Person p1 = new Person(); Person   p2 = (Person) p1.clone();  p1.name = "AAA"; p2.name   = "BBB";  Log.e("TAG", p1.name.toString());   //AAA Log.e("TAG", p2.name.toString()); //BBB } catch   (CloneNotSupportedException e) { e.printStackTrace();}
这个例子中我们期待的输出应该都是BBB,实际上输出的结果是AAA和BBB。这是因为String类型被final修饰符修饰,在内存中是不可以被改变的对象,每次对新的字符串赋值都会分配一块新内存,并指向它。所以String类型在clone中属于特殊情况。
    二、浅拷贝
    回归真题,clone()属于浅拷贝,那么怎么去验证它呢?下面我们对Person增加Hand(手)引用类型,然后再Hand(手)中又增加Finger(手指)引用类型,代码如下
public class Person implements   Cloneable{  public String name; public int age; public   Hand hand;  public Person(Hand hand) {  this.hand =   hand; }  @Override protected Object clone() throws CloneNotSupportedException   {  return super.clone(); }}
    public class Hand { public Finger finger;  public   Hand(Finger finger) {  this.finger = finger; }}
    public class Finger { }
    我们通过比较Person里和Hand里和Finger里的引用类型的地址是否相同,可以看出clone()的本质是浅拷贝
try { Person p1 = new Person(new Hand(new   Finger())); Person p2 = (Person)   p1.clone();  Log.e("TAG", "" +   p1.hand); Log.e("TAG", "" +   p2.hand);  Log.e("TAG", "" +   p1.hand.finger); Log.e("TAG", "" +   p2.hand.finger); } catch (CloneNotSupportedException e)   { e.printStackTrace();}
输出结果可以看出,clone()引用类型的地址是相同的
com.hensen.fashionsource.Hand@38b31e93com.hensen.fashionsource.Hand@38b31e93com.hensen.fashionsource.Finger@3046fed0com.hensen.fashionsource.Finger@3046fed0
三、深拷贝
    如果我们想对Person对象进行深拷贝该怎么做呢?我们可以让Person的引用Hand具有拷贝的功能,那么很自然的可以在Person拷贝的时候拷贝一份Hand,所以Hand我们对Hand实现Cloneable接口,让其具备克隆功能。
public class Person implements   Cloneable{  public String name; public int age; public   Hand hand;  public Person(Hand hand) {  this.hand =   hand; }  @Override protected Object clone() throws CloneNotSupportedException   {  Person newPer = (Person) super.clone();  newPer.hand =   (Hand) hand.clone();  return newPer; }} public class Hand   implements Cloneable{ public Finger finger;  public Hand(Finger   finger) {  this.finger =   finger; }  @Override protected Object clone() throws   CloneNotSupportedException {  return super.clone(); }}
下面我们继续输出拷贝前p1的地址和拷贝后p2的地址,我们可以发现Hand已经完成了深拷贝了
?1234com.hensen.fashionsource.Hand@38b31e93com.hensen.fashionsource.Hand@3046fed0com.hensen.fashionsource.Finger@14be0ec9com.hensen.fashionsource.Finger@14be0ec9
接着,就剩下Finger类了,同样我们重复上面的步骤即可,对Finder类和Hand类改造
public class Hand implements   Cloneable{ public Finger finger;  public Hand(Finger finger)   {  this.finger = finger; }  @Override protected   Object clone() throws CloneNotSupportedException {  Hand newHand =   (Hand) super.clone();  newHand.finger = (Finger)   finger.clone();  return newHand; }} public class Finger   implements Cloneable{  @Override protected Object clone()   throws CloneNotSupportedException {  return   super.clone(); }}
下面我们继续输出拷贝前p1的地址和拷贝后p2的地址,我们可以发现Finger已经完成了深拷贝了
com.hensen.fashionsource.Hand@38b31e93com.hensen.fashionsource.Hand@3046fed0com.hensen.fashionsource.Finger@14be0ec9com.hensen.fashionsource.Finger@35e3b9ce
总结
    至此,Person对象已经完成了完整的深拷贝,这里简单的总结上面的所有内容
clone的使用必须实现Cloneable的接口 clone属于浅拷贝,当可以通过复写clone()实现深拷贝 clone对String类型的拷贝具有特殊性。    

本文由职坐标整理并发布,希望对同学们有所帮助。了解更多详情请关注移动开发之Android频道!

本文由 @凌雪 发布于职坐标。未经许可,禁止转载。
喜欢 | 0 不喜欢 | 0
看完这篇文章有何感觉?已经有0人表态,0%的人喜欢 快给朋友分享吧~
评论(0)
后参与评论

您输入的评论内容中包含违禁敏感词

我知道了

助您圆梦职场 匹配合适岗位
验证码手机号,获得海同独家IT培训资料
选择就业方向:
人工智能物联网
大数据开发/分析
人工智能Python
Java全栈开发
WEB前端+H5

请输入正确的手机号码

请输入正确的验证码

获取验证码

您今天的短信下发次数太多了,明天再试试吧!

提交

我们会在第一时间安排职业规划师联系您!

您也可以联系我们的职业规划师咨询:

小职老师的微信号:z_zhizuobiao
小职老师的微信号:z_zhizuobiao

版权所有 职坐标-一站式IT培训就业服务领导者 沪ICP备13042190号-4
上海海同信息科技有限公司 Copyright ©2015 www.zhizuobiao.com,All Rights Reserved.
 沪公网安备 31011502005948号    

©2015 www.zhizuobiao.com All Rights Reserved

208小时内训课程