java深度克隆_java的深度克隆

先做个标记

http://www.iteye.com/topic/182772

http://www.blogjava.net/jerry-zhaoj/archive/2009/10/14/298141.html

关于super.clone的理解

http://hi.baidu.com/%BB%AA%CF%C4%D1%A7%C9%FA%C1%AA%C3%CB/blog/item/7d70a43842622832b8998f86.html

http://tieba.baidu.com/p/938267457

http://topic.csdn.net/u/20080326/09/a48470f3-f2c2-43c4-af56-fa8ffc12b629.html

http://www.iteye.com/topic/1113790

如何查看JDK源码

http://hi.baidu.com/koflance/blog/item/07809915d6f70e5cf3de32dd.html

http://www.iteye.com/topic/1113790

java对象的克隆步骤:

1.类需要实现Cloneable接口

2 覆盖clone方法,调用super.clone即可。如果是复合类型,如数组,集合类,还需要继续clon下去。

类A1只含有原生类型的属性,A2、A3类含有复合类型的属性,实现起来要clone到底,不然只会拷贝一个引用,从而实现浅拷贝(影子拷贝),实际上只有一个堆对象。两个引用实际上指向了一个对象。

A1的实现

publicclassA1implementsCloneable {

publicintage;

publicObject clone() {

A1 o = null;

try{

o = (A1) super.clone();

} catch(CloneNotSupportedException e) {

e.printStackTrace();

}

returno;

}

Object o = newObject();

}

A2的实现:

publicclassA2implementsCloneable {

publicString[] name;

publicObject clone() {

A2 o = null;

try{

o = (A2) super.clone();

o.name = (String[]) name.clone();

} catch(CloneNotSupportedException e) {

e.printStackTrace();

}

returno;

}

publicA2() {

name = newString[2];

}

}

A3是最复杂的

packagecom.tmall;

importjava.util.Vector;

publicclassA3implementsCloneable {

publicString name[];

publicVector claB;

publicA3() {

name = newString[2];

claB = newVector();

}

publicObject clone() {

A3 o = null;

try{

o = (A3) super.clone();

o.name = (String[]) name.clone();// 深度clone

o.claB = newVector();// 将clone进行到底

for(inti =0; i 

B temp = (B) claB.get(i).clone();// 当然Class B也要实现相应clone方法

o.claB.add(temp);

}

} catch(CloneNotSupportedException e) {

e.printStackTrace();

}

returno;

}

}

其中B类的定义:

publicclassB {

publicintage;

publicObject clone() {

B o = null;

try{

o = (B) super.clone();

} catch(CloneNotSupportedException e) {

e.printStackTrace();

}

returno;

}

}

两个测试方法:

publicstaticvoidtestA1(){

A1 a11 = newA1();

A1 a12 = (A1)a11.clone();

a11.age = 10;

a12.age = 20;

System.out.println(a11.age);

System.out.println(a12.age);

}

publicstaticvoidtestA2(){

A2 a1=newA2();

a1.name[0]="a";

a1.name[1]="1";

A2 a2=(A2)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]);

}

运行结果,可以知道成功实现了深拷贝。

进一步研究:

1  . 翻阅cloneable接口的源码,发现是一个空接口,啥都没有。

packagejava.lang;

/**

* A class implements the Cloneable interface to

* indicate to the {@link java.lang.Object#clone()} method that it

* is legal for that method to make a

* field-for-field copy of instances of that class.

* Invoking Object's clone method on an instance that does not implement the

Cloneable interface results in the exception

CloneNotSupportedException being thrown.

* By convention, classes that implement this interface should override

Object.clone (which is protected) with a public method.

* See {@link java.lang.Object#clone()} for details on overriding this

* method.

* Note that this interface does not contain the clone method.

* Therefore, it is not possible to clone an object merely by virtue of the

* fact that it implements this interface.  Even if the clone method is invoked

* reflectively, there is no guarantee that it will succeed.

*

* @author  unascribed

* @version 1.17, 11/17/05

* @see     java.lang.CloneNotSupportedException

* @see     java.lang.Object#clone()

* @since   JDK1.0

*/

publicinterfaceCloneable {

}

在这篇帖子中对这个问题就行了讨论

2.

clone方法的错误使用。

在不止一篇帖子里面,错误地使用了clone这个方法。

作者是这样调用clone方法的:

A a1=newA();

A a2=newA();     **

a2=(A)a1.clone();

其实做一次实验就可以知道,**行是多余的。

A1 a11 =newA1();

A1 a12 = (A1) a11.clone();

A1 a13 = newA1();

System.out.println("a11的地址是"+ a11);

System.out.println("a12的地址是"+ a12);

System.out.println("a13的地址是"+ a13);

a13 = (A1) a11.clone();

System.out.println("a13的地址是"+ a13);

我的电脑运行结果是

a11的地址是com.tmall.A1@c17164

a12的地址是com.tmall.A1@1fb8ee3

a13的地址是com.tmall.A1@61de33

a13的地址是com.tmall.A1@14318bb

说明a12克隆成功;

A1 a12 = (A1) a11.clone();

是没有问题的。

反而实现new 一个对象如a13,在调用clone()方法会多此一举:

A1 a13 =newA1();

a13 = (A1) a11.clone();

可以看到运行结果里面,a13的地址换了两次。第一次是new出来的新对象,第二次是克隆出来的新对象,两次地址都不等于那个被clone的对象a11。

我翻阅了《effectice java》的条款11,“谨慎地覆盖clone”。作者Joshua Bloch(可是google的首席java工程师)第三段写道:

“如果实现cloneable接口是对某个类起到作用,类和它的所有超类都必须遵守一个想当复杂的、不可实施的,并且基本上没有文档说明的协议。由此得到一种语言之外的机制:

无需要调用构造器就可以创建对象”,红色部分也说明了**行new 一个类是多余的。

3. Object类里面的clone定义。

翻看JDK源码,Object类里面的clone方法定义如下

protectednativeObject clone()throwsCloneNotSupportedException;

使用C/C++来实现的。

是“bitwise(逐位)的复制, 将该对象的内存空间完全复制到新的空间中去”这样实现的。

另外这个方法是protected的,不同的包是不能用的。这就可以解释为什么我们不能显示地调用Object.clone()这个方法。因为Object这个类是放在java,lang这个包里面的,而clone()方法是protected的,是不可见的。如果这样写

Object o1 =newObject();

Object o2 = o1.clone();

编译器肯定会报错的:

1337180593_6876.JPG

之前我不理解A类中为什么用super.clone()这样子的写法,现在明白了。

4.  如果一个类实现了Cloneable接口,Object的clone方法就会返回该对象的逐域拷贝,否则就会抛出CloneNotSupportedException异常。

来自《effective java》条款11的第二段话。所以要实现对象的clone,必须实现cloneable接口。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值