- 写在前面的话
- 引言
- 第 1 章 对象入门
- 第 2 章 一切都是对象
- 第 3 章 控制程序流程
- 第 4 章 初始化和清除
- 第 5 章 隐藏实施过程
- 第 6 章 类再生
- 第 7 章 多形性
- 第 8 章 对象的容纳
- 第 9 章 违例差错控制
- 第 10 章 Java IO 系统
- 第 11 章 运行期类型鉴定
- 第 12 章 传递和返回对象
- 第 十三 章 创建窗口和程序片
- 第 14 章 多线程
- 第 15 章 网络编程
- 第 16 章 设计范式
- 第 17 章 项目
- 附录 A 使用非 JAVA 代码
- 附录 B 对比 C++和 Java
- 附录 C Java 编程规则
- 附录 D 性能
- 附录 E 关于垃圾收集的一些话
- 附录 F 推荐读物
12.2.3 使类具有克隆能力
尽管克隆方法是在所有类最基本的 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”作为对克隆能力提供支持的一部分。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论