详细讲述Java中的克隆
上一篇 /
下一篇 2007-08-29 13:47:05
文章类型:
转载
经常听到有人说 java中没有指针。事实如此吗?no,java是有指针的,只不过换了个名字而已,也就是我们经常提到的引用。我们知道,在java中一切都是对象,那么我们如何操控对象?如何在成千上万的对象中找到我们所需的那个对象呢?又是如何让对象按照我们的意思来完成任务的呢? Object o = new Object(); 这是java中最常见的语句了,在这句话中做了三件事。首先声明一个Object类型的变量o,在内存中为对象划分一块地址new Object(),将声明的变量指向内存中的对象。如此一来,我们就可以通过o来操纵对象了。就好像孩子们玩的遥控飞机,在空中飞行的是飞机,而使它做出优美动作的却是孩子们手中的摇控器。 "克隆"是如今听到的较多的词汇,听说已经将某只羊克隆了好几份了。但愿这种技术不要在人身上实验。java中也有"克隆",与现实世界的克隆一样,将一个实际存在的对象拷贝几份。如下: //倒霉的羊ZDNetChina空间0HS;b4Qh]?%U5L public class Sheep implements Cloneable{ .I'@#F(z9l g(iKs0private String name; Md,B/X(I6wW/T
Y;aw%S0public void setName(String arg) {ZDNetChina空间@#]+o'r[J name = arg;ZDNetChina空间8z\_/f{5B_:} }ZDNetChina空间J-x J;@q3fo public String getName() {ZDNetChina空间ilU7p*^(B.DU return name;ZDNetChina空间P$T3xn&~VkV2g }ZDNetChina空间
s``{4b*p'f public Object clone() throws CloneNotSupportedException { c!|qRq5u9u0return super.clone(); %agB`$dZbT8w0}ZDNetChina空间+m0S6\5u\)HIF }ZDNetChina空间Ui9X0x!X;dS;yG //克隆 7b+|$n!C!q\7M.m0public class Main { (|8Y4fJ1B/j@3j0public static void main(String[] args) throws CloneNotSupportedException { 8TE1v1ns,d3Dv VF0Sheep sheep = new Sheep(); //先得到那只羊的实例 j;ow,jF(Q2\ ?0sheep.setName("我是真的"); //给它做个记号ZDNetChina空间d9^@;Z4}F\$c+S System.out.println("sheep.getName() = " + sheep.getName());ZDNetChina空间g N7n:|$y` uI Sheep sheepClone = (Sheep)sheep.clone(); //开始克隆 il*fw.y;}:D
WJ0System.out.println("sheepClone.getName() = " + sheepClone.getName());ZDNetChina空间rpI6j*k'Tm } (}i4Aj2S+Z0} |
运行程序结果为: sheep.getName() = 我是真的 sheepClone.getName() = 我是真的 两只羊是一模一样的(哪怕那只羊瘸腿)。让我们来看看代码。首先要注意的是Sheep类实现了Cloneable接口(该接口属于java.lang包,默认已经导入了),该接口中并没有定义要实现的方法,是个空接口,起标志作用。也就是说,实现了这个接口的羊就不再是只普通的羊,它是一只可以被克隆的羊。再往下看,有个clone方法,返回Object类型的对象,并抛出CloneNotSupportedException异常。该方法覆写了父类 (Object)的clone方法,并在最后调用了super.clone(),这也意味着无论clone类继承结构是什么样的,super.clone ()都会直接或间接调用Object类的clone()方法。看看jdk帮助文档会发现,Object类的clone()是一个native方法,我们知道,native方法的效率一般来说都是远高于java中的非native方法。这也说明了new一个对象,然后将原对象中的数据导入到新创建的对象中去的做法是多么愚蠢。必须说明的是Object中的clone方法是protected的,所以要使用clone就必须继承Object类(默认)。并且为了可以使其它类调用该方法,必须将其作用域设置为public. 以上只是一个简单clone的实现。明天说说"影子clone"和"深度clone". 夜,深了。何为影子clone?先看一下例子。 //倒霉的羊ZDNetChina空间$rW`R&t+v public class Sheep implements Cloneable{ .Rf-[2M+dBx0private String name;ZDNetChina空间-XL`OukD2}C
E"L public void setName(String arg) {ZDNetChina空间R Wj)\g]:~C name = arg;ZDNetChina空间}o(N!j:q3{0B
\V } 0S,DL ILf!l)k R6_0public String getName() {ZDNetChina空间K4dB|\oc.BD return name;ZDNetChina空间:yK(OPn4rG
T3C } 6f"{s+WP|c0public Object clone() throws CloneNotSupportedException {ZDNetChina空间@F)t&Gbt return super.clone();ZDNetChina空间:Ubo1`.uB6@q$n } RVgQi#p1n\0} 9@E ooQ_mO0//羊圈 Q~vK5f/vW0public class Sheepfold implements Cloneable { ds(l$a4v$wl)d/x;j0public Sheep sheep; 4J\ Q2g1sZ1U(}.E4M0public String name;ZDNetChina空间 T)Mm!y|"A.R[ public Sheepfold() {ZDNetChina空间 p|cX:{8g/P,hW sheep = new Sheep(); kMj#w9T2[&W"](P9FH0}ZDNetChina空间~"? {J;^4Ni.J"M public Object clone() throws CloneNotSupportedException { !?]&S'Z
\$_ a%^K0return super.clone();ZDNetChina空间szq!n+Zq rQM,Yv^ }ZDNetChina空间e3tq$xC;O }ZDNetChina空间Ig6I*CNst%r //克隆ZDNetChina空间4YEu8e9d n0`f8\ public class Main { a|.OM3?b0public static void main(String[] args) throws Exception {ZDNetChina空间JAR:e
?6pO1[Q Sheepfold fold = new Sheepfold();ZDNetChina空间yWy7|)~%{8t fold.name = "小羊圈";ZDNetChina空间,UJ*Th{ss] fold.sheep.setName("小羊");ZDNetChina空间8Xh"Ch|Zo Sheepfold fold2 = (Sheepfold)fold.clone(); `R_S*Q }}1L/]0System.out.println(" fold2.name = " + fold2.name);ZDNetChina空间| oX"`1H} System.out.println(" fold2.sheep.getName() = " + fold2.sheep.getName());ZDNetChina空间.| Vxm'\!H4\kr fold2.name = "大羊圈";ZDNetChina空间Fc r w.J fold2.sheep.setName("大羊");ZDNetChina空间(XQ/^Y
qJ}"s System.out.println("=====================================");ZDNetChina空间 `]l x3~.Z.^]g{cZ System.out.println(" fold2.name = " + fold2.name);ZDNetChina空间@S] [[[ System.out.println("* fold2.sheep.getName() = " + fold2.sheep.getName()); 9?0u+t0b#{:~*?r0System.out.println(" fold.name = " + fold.name);ZDNetChina空间7[-j4Q"J+M+R,X0O:_ System.out.println("* fold.sheep.getName() = " + fold.sheep.getName());ZDNetChina空间K6x2q&n:l System.out.println("====================================="); zWh aFnOhGm0}ZDNetChina空间:I])v];yJ;TC } |
在这个例子中有三个类,Sheep和Sheepflod都实现了Cloneable接口,并且覆写了Object类的clone方法,说明这两个类是具有克隆能力的。注意一点,在Sheepflod中持有一个Sheep的实例,并在Main类中对其进行克隆,结果如下: 请注意一下结果中带有"*"号的两条结果语句。fold2.sheep和fold.sheep的name都变为了"大羊",很奇怪是吗?在此之前,我们只对fold2.sheep的name赋过值。为什么fold.sheep的name也变为了"大羊"呢?原因很简单,因为它们是指向同一个对象的不同引用。从中可以看出,调用Object类中clone()方法时,首先在内存中划分一块同原对象相同的空间,然后将原对象的内容原样拷贝至新对象。我们知道,java中有基本数据类型,对于基本数据类型,这样的操作是没有问题的,但对非基本类型变量,它们保存的仅仅是对象的引用,这也是为什么clone后非基本类型变量和原对象中的变量指向同一个对象的原因。可能你已经注意到,程序中用到了String类型,即对象,为什么没有出现引用指向同一地址的情况?这是因为String是一个不可更改的类(immutable class),每次给它赋值时,都会产生一个新的String对象。如 String str = "a"; str += "b";在这两句代码中,当执行str += "b"时,实际上是重新成生了一个值为"ab"的 String对象,即重新分配了一块内存空间。以上clone方法通常被称为"影子clone"."影子clone"给我们留下了一个问题,即多个引用指向同一个对象。如何解决该问题呢?答案为"深度clone".把上面的例子改成深度clone很简单,只需将Sheepfold的clone()方法改为如下即可:很简单,只需将Sheepfold的clone()方法改为如下即可:ZDNetChina空间'|*|t$k|FEL,X/~
U
public Object clone() throws CloneNotSupportedException { u Ng4t)i!z1J0Sheepfold fold = (Sheepfold)super.clone();ZDNetChina空间6ee
Pow3V*X#n y sheep = (Sheep)fold.sheep.clone();ZDNetChina空间s*JMJ2HF6}G return fold;ZDNetChina空间B+\'{?j`4HT } |
相关阅读:
- Java的开源项目:简单介绍Log4J的使用 (filter, 2007-7-26)
- 简述构建高性能J2EE应用的五种核心策略 (filter, 2007-7-27)
- 最简单的java分页算法 (烂泥, 2007-8-23)
- JSP网站登录记忆跳转实现的一种方法 (小榕, 2007-8-23)
- JSP数据库基础知识 语法详解 (safexx, 2007-8-23)
- JPCAP——Java中的数据链路层控制 (safexx, 2007-8-25)
- JPCAP——Java中的数据链路层控制(二) (safexx, 2007-8-25)
- Java有能力抵挡LAMP的进攻吗? (safexx, 2007-8-27)
- Java继承时构造函数的调用 (烂泥, 2007-8-27)
- JAVA知识:Class.forName的含义 (小榕, 2007-8-28)
导入论坛
引用链接
收藏
分享给好友
推荐到圈子
管理
举报
TAG:
java
标题搜索
日历
|
|
| 日 |
一 |
二 |
三 |
四 |
五 |
六 |
| | | | | | 1 | 2 | | 3 | 4 | 5 | 6 | 7 | 8 | 9 | | 10 | 11 | 12 | 13 | 14 | 15 | 16 | | 17 | 18 | 19 | 20 | 21 | 22 | 23 | | 24 | 25 | 26 | 27 | 28 | 29 | 30 | | 31 | | | | | | |
数据统计
- 访问量: 16352
- 日志数: 102
- 图片数: 1
- 建立时间: 2007-08-17
- 更新时间: 2007-12-12
|