JAVA克隆对象CLONE的用法和作用 电脑资料.docx

上传人:b****4 文档编号:4627324 上传时间:2022-12-07 格式:DOCX 页数:5 大小:19.57KB
下载 相关 举报
JAVA克隆对象CLONE的用法和作用 电脑资料.docx_第1页
第1页 / 共5页
JAVA克隆对象CLONE的用法和作用 电脑资料.docx_第2页
第2页 / 共5页
JAVA克隆对象CLONE的用法和作用 电脑资料.docx_第3页
第3页 / 共5页
JAVA克隆对象CLONE的用法和作用 电脑资料.docx_第4页
第4页 / 共5页
JAVA克隆对象CLONE的用法和作用 电脑资料.docx_第5页
第5页 / 共5页
亲,该文档总共5页,全部预览完了,如果喜欢就下载吧!
下载资源
资源描述

JAVA克隆对象CLONE的用法和作用 电脑资料.docx

《JAVA克隆对象CLONE的用法和作用 电脑资料.docx》由会员分享,可在线阅读,更多相关《JAVA克隆对象CLONE的用法和作用 电脑资料.docx(5页珍藏版)》请在冰豆网上搜索。

JAVA克隆对象CLONE的用法和作用 电脑资料.docx

JAVA克隆对象CLONE的用法和作用电脑资料

java克隆对象clone()的用法和作用电脑资料

假设需修改一个对象,同时不想改变调用者的对象,就要制作该对象的一个本地副本,

假设需修改一个对象,同时不想改变调用者的对象,就要制作该对象的一个本地副本。

这也是本地副本最常见的一种用途。

假设决定制作一个本地副本,只需简单地使用clone()方法即可。

Clone是“克隆”的意思,即制作完全一模一样的副本。

这个方法在根底类Object中定义成“protected”(受保护)模式。

但在希望克隆的任何衍生类中,必须将其覆盖为“public”模式。

例如,标准库类Vector覆盖了clone(),所以能为Vector调用clone(),如下所示:

clone()方法产生了一个Object,后者必须立即重新造型为正确类型。

这个例子指出Vector的clone()方法不能自动尝试克隆Vector内包含的每个对象——由于别名问题,老的Vector和克隆的Vector都包含了相同的对象。

我们通常把这种情况叫作“简单”或者“浅层”,因为它只了一个对象的“外表”局部。

实际对象除包含这个“外表”以外,还包括句柄指向的所有对象,以及那些对象又指向的其他所有对象,由此类推。

这便是“对象网”或“对象关系网”的由来。

假设能下所有这张网,便叫作“全面”或者“深层”。

在输出中可看到浅层的结果,注意对v2采取的行动也会影响到v:

一般来说,由于不敢保证Vector里包含的对象是“可以克隆”(注释②)的,所以最好不要试图克隆那些对象。

尽管克隆方法是在所有类最根本的Object中定义的,但克隆仍然不会在每个类里自动进行。

这似乎有些,因为根底类方法在衍生类里是肯定能用的。

但Java确实有点儿反其道而行之;如果想在一个类里使用克隆方法,唯一的方法就是专门添加一些代码,以便保证克隆的正常进行。

使用protected时的技巧

为防止我们创立的每个类都默认具有克隆能力,clone()方法在根底类Object里得到了“保存”(设为protected)。

这样造成的后果就是:

对那些简单地使用一下这个类的客户程序员来说,他们不会默认地拥有这个方法;其次,我们不能利用指向根底类的一个句柄来调用clone()(尽管那样做在某些情况下特别有用,比方用多形性的方式克隆一系列对象)。

在编译期的时候,这实际是通知我们对象不可克隆的一种方式——而且最奇怪的是,Java库中的大多数类都不能克隆。

因此,假设我们执行下述代码:

Integerx=newInteger(l);

x=x.clone();

那么在编译期,就有一条讨厌的错误弹出,告诉我们不可访问clone()——因为Integer并没有覆盖它,而且它对protected版本来说是默认的)。

但是,假假设我们是在一个从Object衍生出来的类中(所有类都是从Object衍生的),就有权调用Object.clone(),因为它是“protected”,而且我们在一个继承器中。

根底类clone()提供了一个有用的功能——它进行的是对衍生类对象的真正“按位”,所以相当于标准的克隆行动。

然而,我们随后需要将自己的克隆操作设为public,否那么无法访问。

总之,克隆时要注意的两个关键问题是:

几乎肯定要调用super.clone(),以及注意将克隆设为public。

有时还想在更深层的衍生类中覆盖clone(),否那么就直接使用我们的clone()(现在已成为public),而那并不一定是我们所希望的(然而,由于Object.clone()已制作了实际对象的一个副本,所以也有可能允许这种情况)。

protected的技巧在这里只能用一次:

首次从一个不具备克隆能力的类继承,而且想使一个类变成“能够克隆”。

而在从我们的类继承的任何场合,clone()方法都是可以使用的,因为Java不可能在衍生之后反而缩小方法的访问范围。

换言之,一旦对象变得可以克隆,从它衍生的任何东西都是能够克隆的,除非使用特殊的机制(后面讨论)令其“关闭”克隆能力。

实现Cloneable接口

为使一个对象的克隆能力功成圆满,还需要做另一件事情:

实现Cloneable接口。

这个接口使人稍觉奇怪,因为它是空的!

inteCloneable{}

之所以要实现这个空接口,显然不是因为我们准备上溯造型成一个Cloneable,以及调用它的某个方法。

有些人认为在这里使用接口属于一种“欺骗”行为,因为它使用的特性打的是别的主意,而非原来的意思。

Cloneableinte的实现扮演了一个标记的角色,封装到类的类型中。

两方面的原因促成了Cloneableinte的存在。

首先,可能有一个上溯造型句柄指向一个根底类型,而且不知道它是否真的能克隆那个对象。

在这种情况下,可用instanof关键字(第11章有介绍)调查句柄是否确实同一个能克隆的对象连接:

if(myHandleinstanofCloneable)//…

第二个原因是考虑到我们可能不愿所有对象类型都能克隆。

所以Object.clone()会验证一个类是否真的是实现了Cloneable接口。

假设答案是否认的,那么“掷”出一个CloneNotSupportedExption违例。

所以在一般情况下,我们必须将“implementCloneable”作为对克隆能力提供支持的一局部。

理解了实现clone()方法背后的所有细节后,便可创立出能方便的类,以便提供了一个本地副本:

不管怎样,clone()必须能够访问,所以必须将其设为public(公共的)。

其次,作为clone()的初期行动,应调用clone()的根底类版本。

这里调用的clone()是Object内部预先定义好的。

之所以能调用它,是由于它具有protected(受到保护的)属性,所以能在衍生的类里访问。

Object.clone()会检查原先的对象有多大,再为新对象腾出足够多的内存,将所有二进制位从原来的对象到新对象。

这叫作“按位”,而且按一般的想法,这个工作应该是由clone()方法来做的。

但在Object.clone()正式开始操作前,首先会检查一个类是否Cloneable,即是否具有克隆能力——换言之,它是否实现了Cloneable接口。

假设未实现,Object.clone()就掷出一个CloneNotSupportedExption违例,指出我们不能克隆它。

因此,我们最好用一个try-catch块将对super.clone()的调用代码包围(或封装)起来,试图捕获一个应当永不出现的违例(因为这里确实已实现了Cloneable接口)。

在LocalCopy中,两个方法g()和f()揭示出两种参数传递方法间的差异。

其中,g()演示的是按引用传递,它会修改外部对象,并返回对那个外部对象的一个引用。

而f()是对自变量进行克隆,所以将其别离出来,并让原来的对象保持。

随后,它继续做它希望的事情。

甚至能返回指向这个新对象的一个句柄,而且不会对原来的对象产生任何副作用。

注意下面这个多少有些乖僻的语句:

v=(MyObject)v.clone();

它的作用正是创立一个本地副本。

为防止被这样的一个语句搞混淆,记住这种相当奇怪的编码形式在Java中是完全允许的,因为有一个名字的所有东西实际都是一个句柄。

所以句柄v用于克隆一个它所指向的副本,而且最终返回指向根底类型Object的一个句柄(因为它在Object.clone()中是那样被定义的),随后必须将其造型为正确的类型。

在in()中,两种不同参数传递方式的区别在于它们分别测试了一个不同的方法。

输出结果如下:

大家要记住这样一个事实:

Java对“是否等价”的测试并不对所比拟对象的内部进行检查,从而核实它们的值是否相同。

==和!

=运算符只是简单地比照句柄的内容。

假设句柄内的地址相同,就认为句柄指向同样的对象,所以认为它们是“等价”的。

所以运算符真正检测的是“由于别名问题,句柄是否指向同一个对象?

调用Object.clone()时,实际发生的是什么事情呢?

当我们在自己的类里覆盖clone()时,什么东西对于super.clone()来说是最关键的呢?

根类中的clone()方法负责建立正确的存储容量,并通过“按位”将二进制位从原始对象中到新对象的存储空间。

也就是说,它并不只是预留存储空间以及一个对象——实际需要调查出欲之对象的准确大小,然后那个对象。

由于所有这些工作都是在由根类定义之clone()方法的内部代码中进行的(根类并不知道要从自己这里继承出去什么),所以大家或许已经猜到,这个过程需要用RTTI判断欲克隆的对象的实际大小。

采取这种方式,clone()方法便可建立起正确数量的存储空间,并对那个类型进行正确的按位。

不管我们要做什么,克隆过程的第一个局部通常都应该是调用super.clone()。

通过进行一次准确的,这样做可为后续的克隆进程建立起一个良好的根底。

随后,可采取另一些必要的操作,以完成最终的克隆。

为确切了解其他操作是什么,首先要正确理解Object.clone()为我们带来了什么。

特别地,它会自动克隆所有句柄指向的目标吗?

下面这个例子可完成这种形式的检测:

一条Snake(蛇)由数段构成,每一段的类型都是Snake,

increment()方法的作用是循环递增每个标记,使我们能看到发生的变化;而toString那么循环打印出每个标记。

输出如下:

s=:

a:

b:

c:

d:

e

s2=:

a:

b:

c:

d:

e

afters.increment,s2=:

a:

c:

d:

e:

f

这意味着只有第一段才是由Object.clone()的,所以此时进行的是一种“浅层”。

假设希望整条蛇——即进行“深层”——必须在被覆盖的clone()里采取附加的操作。

通常可在从一个能克隆的类里调用super.clone(),以确保所有根底类行动(包括Object.clone())能够进行。

随着是为对象内每个句柄都明确调用一个clone();否那么那些句柄会别名变成原始对象的句柄。

构建器的调用也大致相同——首先构造根底类,然后是下一个衍生的构建器……以此类推,直到位于最深层的衍生构建器。

区别在于clone()并不是个构建器,所以没有方法实现自动克隆。

为了克隆,必须由自己明确进行。

试图深层合成对象时会遇到一个问题。

必须假定成员对象中的clone()方法也能依次对自己的句柄进行深层,以此类推。

这使我们的操作变得复杂。

为了能正常实现深层,必须对所有类中的代码进行控制,或者至少全面掌握深层中需要涉及的类,确保它们自己的深层能正确进行。

下面这个例子了面对一个合成对象进行深层时需要做哪些事情:

DepthReading和TemperatureReading非常相似;它们都只包含了根本数据类型。

所以clone()方法能够非常简单:

调用super.clone()并返回结果即可。

注意两个类使用的clone()代码是完全一致的。

OanReading是由DepthReading和TemperatureReading对象合并而成的。

为了对其进行深层,clone()必须同时克隆OanReading内的句柄。

为到达这个目标,super.clone()的结果必须造型成一个OanReading对象(以便访问depth和temperature句柄)。

java.lang.Object里面有一个方法clone()

protectedObjectclone()

throwsCloneNotSupportedExption创立并返回此对象的一个副本。

“副本”的准确含义可能依赖于对象的类。

这样做的目的是,对于任何对象x,表达式:

x.clone()!

=x为true,表达式:

x.clone().getClass()==x.getClass()也为true,但这些并非必须要满足的要求。

一般情况下:

x.clone().equals(x)为true,但这并非必须要满足的要求。

按照惯例,返回的对象应该通过调用super.clone获得。

如果一个类及其所有的超类(Object除外)都遵守此约定,那么x.clone().getClass()==x.getClass()。

按照惯例,此方法返回的对象应该于该对象(正被的对象)。

要获得此性,在super.clone返回对象之前,有必要对该对象的一个或多个字段进行修改。

这通常意味着要包含正在被对象的内部“深层结构”的所有可变对象,并使用对副本的引用替换对这些对象的引用。

如果一个类只包含根本字段或对不变对象的引用,那么通常不需要修改super.clone返回的对象中的字段。

Object类的clone方法执行特定的操作。

首先,如果此对象的类不能实现接口Cloneable,那么会抛出CloneNotSupportedExption。

注意,所有的数组都被视为实现接口Cloneable。

否那么,此方创立此对象的类的一个新实例,并像通过分配那样,严格使用此对象相应字段的内容初始化该对象的所有字段;这些字段的内容没有被自我。

所以,此方法执行的是该对象的“浅表”,而不“深层”操作。

Object类本身不实现接口Cloneable,所以在类为Object的对象上调用clone方法将会导致在运行时抛出异常。

返回:

此实例的一个副本。

抛出:

CloneNotSupportedExption-如果对象的类不支持Cloneable接口,那么重写clone方法的子类也会抛出此异常,以指示无法某个实例。

运行结果如下:

 

模板,内容仅供参考

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 初中教育 > 语文

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1