java clone()方法使用解析以及深/浅拷贝
2014-09-29 12:51
537 查看
Java代码
publicclassA{
publicStringname;
}
Java代码
publicclasstestClone{
publicvoidchangeA(Aa){
a.name="b";
}
publicvoidchangInt(inti){
i=i*2+100;
}
/**
*@paramargs
*/
publicstaticvoidmain(String[]args){
//TODOAuto-generatedmethodstub
testClonetest=newtestClone();
Aa=newA();
a.name="a";
System.out.println("beforechange:a.name="+a.name);
test.changeA(a);
System.out.println("afterchange:a.name="+a.name);
inti=1;
System.out.println("beforechange:i="+i);
test.changInt(i);
System.out.println("afterchange:i="+i);
}
}
此时输出的结果是:
Java代码
beforechange:a.name=a
afterchange:a.name=b
beforechange:i=1
afterchange:i=1
从这个例子知道Java对对象和基本的数据类型的处理是不一样的。在Java中用对象的作为入口参数的传递则缺省为"引用传递",也就是说仅仅传递了对象的一个"引用",这个"引用"的概念同C语言中的指针引用是一样的。当函数体内部对输入变量改变时,实质上就是在对这个对象的直接操作。
除了在函数传值的时候是"引用传递",在任何用"="向对象变量赋值的时候都是"引用传递",如:
Java代码
Aa1=newA();
Aa2=newA();
a1.name="a1";
a2=a1;
a2.name="a2";
System.out.println("a1.name="+a1.name);
System.out.println("a2.name="+a2.name);
此时输出的结果是:
Java代码
a1.name=a2
a2.name=a2
如果我们要用a2保存a1对象的数据,但又不希望a2对象数据被改变时不影响到a1。实现clone()方法是其一种最简单,也是最高效的手段。
下面我们来实现A的clone方法
Java代码
publicclassAimplementsCloneable{
publicStringname;
publicObjectclone(){
Ao=null;
try{
o=(A)super.clone();
}catch(CloneNotSupportedExceptione){
e.printStackTrace();
}
returno;
}
}
(浅拷贝,生成新对象,只拷贝8种基本类型+String类型的值,引用对象类型的只复制引用地址,对其修改会影响引用对象本身)首先要实现Cloneable接口,然后在重载clone方法,最后在clone()方法中调用了super.clone(),这也意味着无论clone类的继承结构是什么样的,super.clone()直接或间接调用了java.lang.Object类的clone()方法。
Java代码
Aa1=newA();
Aa2=newA();
a1.name="a1";
a2=a1;
a2.name="a2";
System.out.println("a1.name="+a1.name);
System.out.println("a2.name="+a2.name);
此时输出的结果是:
Java代码
a1.name=a1
a2.name=a2
当ClassA成员变量类型是java的基本类型时(外加String类型),只要实现如上简单的clone(称影子clone)就可以。但是如果ClassA成员变量是数组或复杂类型时,就必须实现深度clone。(深拷贝,对引用对象类型的值也进行拷贝,调用每个引用对象本身的clone方法,一般实现一层深度拷贝,如果存在多层拷贝,则需要每层都要写拷贝函数,因此要避免拷贝循环问题。)
2. publicWorkExperience(){ }
3. publicWorkExperienceclone()throwsCloneNotSupportedException{
4. return(WorkExperience)super.clone();
5. }
6. }
7. classDeepResumeimplementsCloneable{
8. privateStringname;
9. privateWorkExperiencework;
10. publicResume(Stringname){
11. this.name=name;
12. }
13. @Override
14. publicDeepResumeclone()throwsCloneNotSupportedException{
15. Resumeobj=(DeepResume)super.clone();
16. obj.work=(WorkExperience)work.clone();
17. returnobj;
18. }
19. }
Java代码
publicclassAimplementsCloneable{
publicStringname[];
publicA(){
name=newString[2];
}
publicObjectclone(){
Ao=null;
try{
o=(A)super.clone();
}catch(CloneNotSupportedExceptione){
e.printStackTrace();
}
returno;
}
}
测试代码
Java代码
Aa1=newA();
Aa2=newA();
a1.name[0]="a";
a1.name[1]="1";
a2=(A)a1.clone();
a2.name[0]="b";
a2.name[1]="1";
System.out.println("a1.name="+a1.name);
System.out.println("a1.name="+a1.name[0]+a1.name[1]);
System.out.println("a2.name="+a2.name);
System.out.println("a2.name="+a2.name[0]+a2.name[1]);
输出结果:
Java代码
a1.name=[Ljava.lang.String;@757aef
a1.name=b1
a2.name=[Ljava.lang.String;@757aef
a2.name=b1
看到了吧,a1.name,a2.name的hash值都是@757aef,也就是说影子clone对name数组只是clone他们的地址!解决该办法是进行深度clone。
Java代码
publicObjectclone(){
Ao=null;
try{
o=(A)super.clone();
o.name=(String[])name.clone();//其实也很简单^_^
}catch(CloneNotSupportedExceptione){
e.printStackTrace();
}
returno;
}
此时输出结果是:
Java代码
a1.name=[Ljava.lang.String;@757aef
a1.name=a1
a2.name=[Ljava.lang.String;@d9f9c3
a2.name=b1
需要注意的是ClassA存在更为复杂的成员变量时,如Vector等存储对象地址的容器时,就必须clone彻底。
Java代码
publicclassAimplementsCloneable{
publicStringname[];
publicVector<B>claB;
publicA(){
name=newString[2];
claB=newVector<B>();
}
publicObjectclone(){
Ao=null;
try{
o=(A)super.clone();
o.name==(String[])name.clone();//深度clone
o.claB=newVector<B>();//将clone进行到底
for(inti=0;i<claB.size();i++){
Btemp=(B)claB.get(i).clone();//当然ClassB也要实现相应clone方法
o.claB.add(temp);
}
}catch(CloneNotSupportedExceptione){
e.printStackTrace();
}
returno;
}
}
相关文章推荐
- java中equals和==之间的区别?clone方法的作用,及其为什么要使用clone方法?如何使用clone复制对象?以及深克隆浅克隆
- Java解析json文件的方法--直接拷贝可以使用
- (3) java.lang.Object.clone()方法 以及 深拷贝浅拷贝 及其 实现
- Java clone方法深拷贝浅拷贝完全解析
- JAVA克隆详解以及clone方法使用
- 五星-原型模式常使用于以下场景--而JAVA中的任何类只要实现了Cloneable标识接口,就可以使用clone方法来进行对象的拷贝
- java的反射(构造函数,属性,方法)以及JAXP解析DOM文档
- oracle pl/sql应用解析以及存储过程对应到java中的调用方法
- 【转】 java clone方法使用详解
- java clone方法使用详解
- Java clone方法使用详解
- java URL以及UrlConnection使用解析
- 使用Java解析网络数据流的三种特殊方法
- gx + java 中,结构体类型SDT(Struct Data Type)的Clone()方法使用
- 使用beanShell来解析执行java的String方法,类似javascipt的eval方法
- JAVA获取JVM内存使用以及服务器CPU,硬盘使用方法
- javacc xxxTokenManager类作用 以及重要方法解析
- Java中包的使用以及类、方法的说明符
- java clone方法使用详解
- [Java Eclipse] 使用Eclipse发布jar包以及制作exe文件的方法