摘要:本文将带你了解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频道!
您输入的评论内容中包含违禁敏感词
我知道了
请输入正确的手机号码
请输入正确的验证码
您今天的短信下发次数太多了,明天再试试吧!
我们会在第一时间安排职业规划师联系您!
您也可以联系我们的职业规划师咨询:
版权所有 职坐标-一站式IT培训就业服务领导者 沪ICP备13042190号-4
上海海同信息科技有限公司 Copyright ©2015 www.zhizuobiao.com,All Rights Reserved.
沪公网安备 31011502005948号