使类具有克隆能力

尽管克隆方法是在所有类最基本的Object中定义的,但克隆仍然不会在每个类里自动进行。这似乎有些不可思议,因为基础类方法在衍生类里是肯定能用的。但Java确实有点儿反其道而行之;如果想在一个类里使用克隆方法,唯一的办法就是专门添加一些代码,以便保证克隆的正常进行。

1. 使用protected时的技巧
为避免我们创建的每个类都默认具有克隆能力,clone()方法在基础类Object里得到了“保留”(设为protected)。这样造成的后果就是:对那些简单地使用一下这个类的客户程序员来说,他们不会默认地拥有这个方法;其次,我们不能利用指向基础类的一个句柄来调用clone()(尽管那样做在某些情况下特别有用,比如用多形性的方式克隆一系列对象)。在编译期的时候,这实际是通知我们对象不可克隆的一种方式——而且最奇怪的是,Java库中的大多数类都不能克隆。因此,假如我们执行下述代码:
Integer x = new Integer(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不可能在衍生之后反而缩小方法的访问范围。换言之,一旦对象变得可以克隆,从它衍生的任何东西都是能够克隆的,除非使用特殊的机制(后面讨论)令其“关闭”克隆能力。

2. 实现Cloneable接口
为使一个对象的克隆能力功成圆满,还需要做另一件事情:实现Cloneable接口。这个接口使人稍觉奇怪,因为它是空的!
interface Cloneable {}
之所以要实现这个空接口,显然不是因为我们准备上溯造型成一个Cloneable,以及调用它的某个方法。有些人认为在这里使用接口属于一种“欺骗”行为,因为它使用的特性打的是别的主意,而非原来的意思。Cloneable interface的实现扮演了一个标记的角色,封装到类的类型中。
两方面的原因促成了Cloneable interface的存在。首先,可能有一个上溯造型句柄指向一个基础类型,而且不知道它是否真的能克隆那个对象。在这种情况下,可用instanceof关键字(第11章有介绍)调查句柄是否确实同一个能克隆的对象连接:
if(myHandle instanceof Cloneable) // ...
第二个原因是考虑到我们可能不愿所有对象类型都能克隆。所以Object.clone()会验证一个类是否真的是实现了Cloneable接口。若答案是否定的,则“掷”出一个CloneNotSupportedException违例。所以在一般情况下,我们必须将“implement Cloneable”作为对克隆能力提供支持的一部分。

时间: 2024-08-31 07:54:56

使类具有克隆能力的相关文章

《Effective Java》笔记 使类和成员的可访问性最小化

类和接口 第13条 使类和成员的可访问性最小化 1.设计良好的模块会隐藏所有的实现细节,把它的API与实现清晰的隔离开来,模块之间只通过它们的API进行通信,一个模块不需要知道其他模块的内部工作情况:即信息隐藏或封装,是软件设计的基本原则之一. 2.Java提供了许多机制来协助信息隐藏.访问控制(access control)机制决定了类.接口和成员的可访问性(accessibility). 3.第一规则:尽可能地使每个类或者成员不被外界访问.或者说在保证功能的情况下,使用最小的访问级别. 4.

JS扩展类,克隆对象与混合类实例分析_javascript技巧

本文实例讲述了JS扩展类,克隆对象与混合类.分享给大家供大家参考,具体如下: 1.类扩展 /* EditInPlaceField类 */ /* 扩展函数 */ function extend(subClass, superClass) { var F = function() {}; F.prototype = superClass.prototype; subClass.prototype = new F(); subClass.prototype.constructor = subClass

《Java核心技术 卷Ⅱ 高级特性(原书第10版)》一2.4.1 保存和加载序列化对象

2.4.1 保存和加载序列化对象 为了保存对象数据,首先需要打开一个ObjectOutputStream对象: 现在,为了保存对象,可以直接使用ObjectOutputStream的writeObject方法,如下 所示: 为了将这些对象读回,首先需要获得一个ObjectInputStream对象: 然后,用readObject方法以这些对象被写出时的顺序获得它们: 但是,对希望在对象输出流中存储或从对象输入流中恢复的所有类都应进行一下修改,这些类必须实现Serializable接口: Seri

使克隆具有更大的深度

若新建一个类,它的基础类会默认为Object,并默认为不具备克隆能力(就象在下一节会看到的那样).只要不明确地添加克隆能力,这种能力便不会自动产生.但我们可以在任何层添加它,然后便可从那个层开始向下具有克隆能力.如下所示:   //: HorrorFlick.java // You can insert Cloneability at any // level of inheritance. import java.util.*; class Person {} class Hero exten

任志强:保障房缺失使无支付能力家庭被赶入市场

住房公共产品的10年缺失,使那些没有支付能力.应该受到政府保障的家庭被赶入市场 文/本刊记者 赵沛楠 2007年8月国务院发布了<关于解决城市低收入家庭住房困难的若干 意见>(国发[2007]24号,以下简称24号文),这是住房保障政策体系的一个纲领性文件.<意见>明确给出了3种供给关系:一是高收入或中高收入家庭用市场化方式.商品化的方式解决住房问题:二是中等或中等偏下收入的家庭靠半市场化的经济适用住房解决住房问题:三是低收入家庭靠政府廉租房解决住房保障问题. 在接受<中国投

java克隆的控制

为消除克隆能力,大家也许认为只需将clone()方法简单地设为private(私有)即可,但这样是行不通的,因为不能采用一个基础类方法,并使其在衍生类中更"私有".所以事情并没有这么简单.此外,我们有必要控制一个对象是否能够克隆.对于我们设计的一个类,实际有许多种方案都是可以采取的: (1) 保持中立,不为克隆做任何事情.也就是说,尽管不可对我们的类克隆,但从它继承的一个类却可根据实际情况决定克隆.只有Object.clone()要对类中的字段进行某些合理的操作时,才可以作这方面的决定

Java中的类反射机制

一.反射的概念 :反射的概念是由Smith在1982年首次提出的,主要是指程序可以访问.检测和修改它本身状态或行为的一种能力.这一概念的提出很快引发了计算机科学领域关于应用反射性的研究.它首先被程序语言的设计领域所采用,并在Lisp和面向对象方面取得了成绩.其中LEAD/LEAD++ .OpenC++ .MetaXa和OpenJava等就是基于反射机制的语言.最近,反射机制也被应用到了视窗系统.操作系统和文件系统中. 反射本身并不是一个新概念,它可能会使我们联想到光学中的反射概念,尽管计算机科学

学习笔记-Mixin类和多重继承

笔记|继承 Mixins and Introductions 很多人说道AOP,都以为AOP就是截取器,切入点表达式,方面和实现(advices).其实AOP 不止这些,另外一个很重要的功能在JBOSS AOP里面就是可以透明的给JAVA类传入接口.你 可以强制一个类实现的接口,甚至你可以附加另外的类(mixins)来实现这个接口.就像C++ 里面的多重集成. 引入 首先我们介绍怎么强制现有的类来实现你希望它实现的接口. 首先的例子是让一个非可持久化类实现持久化能力.这对你将是十分有用的代码.

sun.misc.unsafe类的用法

这个帖子是关于JAVA中鲜为人知的特性的后续更新,如果想得到下次在线讨论的更新,请通过邮件订阅,并且不要忘了在评论区留下你的意见和建议. Java是一个安全的开发工具,它阻止开发人员犯很多低级的错误,而大部份的错误都是基于内存管理方面的.如果你想搞破坏,可以使用Unsafe这个类.这个类是属于sun.* API中的类,并且它不是J2SE中真正的一部份,因此你可能找不到任何的官方文档,更可悲的是,它也没有比较好的代码文档. 实例化sun.misc.Unsafe 如果你尝试创建Unsafe类的实例,