返回介绍

12.2.5 Object.clone() 的效果

发布于 2024-10-15 23:56:26 字数 2214 浏览 0 评论 0 收藏 0

调用 Object.clone() 时,实际发生的是什么事情呢?当我们在自己的类里覆盖 clone() 时,什么东西对于 super.clone() 来说是最关键的呢?根类中的 clone() 方法负责建立正确的存储容量,并通过“按位复制”将二进制位从原始对象中复制到新对象的存储空间。也就是说,它并不只是预留存储空间以及复制一个对象——实际需要调查出欲复制之对象的准确大小,然后复制那个对象。由于所有这些工作都是在由根类定义之 clone() 方法的内部代码中进行的(根类并不知道要从自己这里继承出去什么),所以大家或许已经猜到,这个过程需要用 RTTI 判断欲克隆的对象的实际大小。采取这种方式,clone() 方法便可建立起正确数量的存储空间,并对那个类型进行正确的按位复制。

不管我们要做什么,克隆过程的第一个部分通常都应该是调用 super.clone()。通过进行一次准确的复制,这样做可为后续的克隆进程建立起一个良好的基础。随后,可采取另一些必要的操作,以完成最终的克隆。

为确切了解其他操作是什么,首先要正确理解 Object.clone() 为我们带来了什么。特别地,它会自动克隆所有句柄指向的目标吗?下面这个例子可完成这种形式的检测:

//: Snake.java
// Tests cloning to see if destination of
// handles are also cloned.

public class Snake implements Cloneable {
  private Snake next;
  private char c;
  // Value of i == number of segments
  Snake(int i, char x) {
    c = x;
    if(--i > 0)
      next = new Snake(i, (char)(x + 1));
  }
  void increment() {
    c++;
    if(next != null)
      next.increment();
  }
  public String toString() {
    String s = ":" + c;
    if(next != null)
      s += next.toString();
    return s;
  }
  public Object clone() {
    Object o = null;
    try {
      o = super.clone();
    } catch (CloneNotSupportedException e) {}
    return o;
  }
  public static void main(String[] args) {
    Snake s = new Snake(5, 'a');
    System.out.println("s = " + s);
    Snake s2 = (Snake)s.clone();
    System.out.println("s2 = " + s2);
    s.increment();
    System.out.println(
      "after s.increment, s2 = " + s2);
  }
} ///:~

一条 Snake(蛇)由数段构成,每一段的类型都是 Snake。所以,这是一个一段段链接起来的列表。所有段都是以循环方式创建的,每做好一段,都会使第一个构建器参数的值递减,直至最终为零。而为给每段赋予一个独一无二的标记,第二个参数(一个 Char)的值在每次循环构建器调用时都会递增。

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

s = :a:b:c:d:e
s2 = :a:b:c:d:e
after s.increment, s2 = :a:c:d:e:f

这意味着只有第一段才是由 Object.clone() 复制的,所以此时进行的是一种“浅层复制”。若希望复制整条蛇——即进行“深层复制”——必须在被覆盖的 clone() 里采取附加的操作。

通常可在从一个能克隆的类里调用 super.clone(),以确保所有基础类行动(包括 Object.clone())能够进行。随着是为对象内每个句柄都明确调用一个 clone();否则那些句柄会别名变成原始对象的句柄。构建器的调用也大致相同——首先构造基础类,然后是下一个衍生的构建器……以此类推,直到位于最深层的衍生构建器。区别在于 clone() 并不是个构建器,所以没有办法实现自动克隆。为了克隆,必须由自己明确进行。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文