友情提示:如果本网页打开太慢或显示不完整,请尝试鼠标右键“刷新”本网页!
第三电子书 返回本书目录 加入书签 我的书架 我的书签 TXT全本下载 『收藏到我的浏览器』

Java编程思想第4版[中文版](PDF格式)-第88部分

快捷操作: 按键盘上方向键 ← 或 → 可快速上下翻页 按键盘上的 Enter 键可回到本书目录页 按键盘上方向键 ↑ 可回到本页顶部! 如果本书没有阅读完,想下次继续接着阅读,可使用上方 "收藏到我的浏览器" 功能 和 "加入书签" 功能!


      t1 = System。currentTimeMillis();  

      Thing4'' d = new Thing4'SIZE';  

      for(int i = 0; i 《 d。length; i++)  

        d'i' = (Thing4)b'i'。clone();  

      t2 = System。currentTimeMillis();  

      System。out。println(  

        〃Duplication via cloning: 〃 +  

        (t2 t1) + 〃 Milliseconds〃);  

    } catch(Exception e) {  

      e。printStackTrace();  

    }  

  }  

} ///:~  

  

其中,Thing2 和 Thing4 包含了成员对象,所以需要进行一些深层复制。一个有趣的地方是尽管 

Serializable 类很容易设置,但在复制它们时却要做多得多的工作。克隆涉及到大量的类设置工作,但实际 

的对象复制是相当简单的。结果很好地说明了一切。下面是几次运行分别得到的结果:  

的确  

Duplication via serialization: 3400 Milliseconds  

Duplication via cloning: 110 Milliseconds  

Duplication via serialization: 3410 Milliseconds  

Duplication via cloning: 110 Milliseconds  

Duplication via serialization: 3520 Milliseconds  

Duplication via cloning: 110 Milliseconds  

  

除了序列化和克隆之间巨大的时间差异以外,我们也注意到序列化技术的运行结果并不稳定,而克隆每一次 

花费的时间都是相同的。  



12。2。9 使克隆具有更大的深度  



若新建一个类,它的基础类会默认为Object,并默认为不具备克隆能力(就象在下一节会看到的那样)。只 

要不明确地添加克隆能力,这种能力便不会自动产生。但我们可以在任何层添加它,然后便可从那个层开始 

向下具有克隆能力。如下所示:  

  

//: HorrorFlick。java  

// You can insert Cloneability at any  

// level of inheritance。  

import java。util。*;  

  



                                                                                          361 


…………………………………………………………Page 363……………………………………………………………

class Person {}  

class Hero extends Person {}  

class Scientist extends Person   

    implements Cloneable {  

  public Object clone() {  

    try {  

      return super。clone();  

    } catch (CloneNotSupportedException e) {  

      // this should never happen:  

      // It's Cloneable already!  

      throw new InternalError();  

    }  

  }  

}  

class MadScientist extends Scientist {}  

  

public class HorrorFlick {  

  public static void main(String'' args) {  

    Person p = new Person();  

    Hero h = new Hero();  

    Scientist s = new Scientist();  

    MadScientist m = new MadScientist();  

  

    // p = (Person)p。clone(); // pile error  

    // h = (Hero)h。clone(); // pile error  

    s = (Scientist)s。clone();  

    m = (MadScientist)m。clone();  

  }  

} ///:~  

  

添加克隆能力之前,编译器会阻止我们的克隆尝试。一旦在Scientist 里添加了克隆能力,那么Scientist 

以及它的所有“后裔”都可以克隆。  



12。2。10 为什么有这个奇怪的设计  



之所以感觉这个方案的奇特,因为它事实上的确如此。也许大家会奇怪它为什么要象这样运行,而该方案背 

后的真正含义是什么呢?后面讲述的是一个未获证实的故事——大概是由于围绕Java 的许多买卖使其成为一 

种设计优良的语言——但确实要花许多口舌才能讲清楚这背后发生的所有事情。  

最初,Java 只是作为一种用于控制硬件的语言而设计,与因特网并没有丝毫联系。象这样一类面向大众的语 

言一样,其意义在于程序员可以对任意一个对象进行克隆。这样一来,clone()就放置在根类Object 里面, 

但因为它是一种公用方式,因而我们通常能够对任意一个对象进行克隆。看来这是最灵活的方式了,毕竟它 

不会带来任何害处。  

正当Java 看起来象一种终级因特网程序设计语言的时候,情况却发生了变化。突然地,人们提出了安全问 

题,而且理所当然,这些问题与使用对象有关,我们不愿望任何人克隆自己的保密对象。所以我们最后看到 

的是为原来那个简单、直观的方案添加的大量补丁:clone()在Object 里被设置成“protected”。必须将其 

覆盖,并使用“implement Cloneable”,同时解决违例的问题。  

只有在准备调用Object 的 clone()方法时,才没有必要使用 Cloneable 接口,因为那个方法会在运行期间得 

到检查,以确保我们的类实现了Cloneable。但为了保持连贯性(而且由于Cloneable 无论如何都是空 

的),最好还是由自己实现Cloneable。  



                                                                                         362 


…………………………………………………………Page 364……………………………………………………………

12。3 克隆的控制  



为消除克隆能力,大家也许认为只需将clone()方法简单地设为private (私有)即可,但这样是行不通的, 

因为不能采用一个基础类方法,并使其在衍生类中更“私有”。所以事情并没有这么简单。此外,我们有必 

要控制一个对象是否能够克隆。对于我们设计的一个类,实际有许多种方案都是可以采取的:  

(1) 保持中立,不为克隆做任何事情。也就是说,尽管不可对我们的类克隆,但从它继承的一个类却可根据 

实际情况决定克隆。只有Object。clone()要对类中的字段进行某些合理的操作时,才可以作这方面的决定。  

(2) 支持 clone(),采用实现 Cloneable (可克隆)能力的标准操作,并覆盖clone()。在被覆盖的clone() 

中,可调用 super。clone(),并捕获所有违例(这样可使clone()不“掷”出任何违例)。  

(3) 有条件地支持克隆。若类容纳了其他对象的句柄,而那些对象也许能够克隆(集合类便是这样的一个例 

子),就可试着克隆拥有对方句柄的所有对象;如果它们“掷”出了违例,只需让这些违例通过即可。举个 

例子来说,假设有一个特殊的 Vector,它试图克隆自己容纳的所有对象。编写这样的一个Vector 时,并不 

知道客户程序员会把什么形式的对象置入这个 Vector 中,所以并不知道它们是否真的能够克隆。  

(4) 不实现 Cloneable(),但是将clone()覆盖成 protected,使任何字段都具有正确的复制行为。这样一 

来,从这个类继承的所有东西都能覆盖clone(),并调用 super。clone()来产生正确的复制行为。注意在我们 

实现方案里,可以而且应该调用super。clone()——即使那个方法本来预期的是一个Cloneable 对象(否则 

会掷出一个违例),因为没有人会在我们这种类型的对象上直接调用它。它只有通过一个衍生类调用;对那 

个衍生类来说,如果要保证它正常工作,需实现Cloneable。  

(5) 不实现 Cloneable 来试着防止克隆,并覆盖clone(),以产生一个违例。为使这一设想顺利实现,只有 

令从它衍生出来的任何类都调用重新定义后的 clone()里的 suepr。clone()。  

(6) 将类设为final,从而防止克隆。若clone()尚未被我们的任何一个上级类覆盖,这一设想便不会成功。 

若已被覆盖,那么再一次覆盖它,并“掷”出一个 CloneNotSupportedException (克隆不支持)违例。为担 

保克隆被禁止,将类设为final 是唯一的办法。除此以外,一旦涉及保密对象或者遇到想对创建的对象数量 

进行控制的其他情况,应该将所有构建器都设为private,并提供一个或更多的特殊方法来创建对象。采用 

这种方式,这些方法就可以限制创建的对象数量以及它们的创建条件——一种特殊情况是第 16 章要介绍的 

singleton (独子)方案。  

  

下面这个例子总结了克隆的各种实现方法,然后在层次结构中将其“关闭”:  

  

//: CheckCloneable。java  

// Checking to see if a handle can be cloned  

  

// Can't clone this because it doesn't  

// override clone():  

class Ordinary {}  

  

// Overrides clone; but doesn't implement  

// Cloneable:  

class WrongClone extends Ordinary {  

  public Object clone()  

      throws CloneNotSupportedException {  

    return super。clone(); // Throws exception  

  }  

}  

  

// Does all the right things for cloning:  

class IsCloneable extends Ordinary   

    implements Cloneable {  

  public Object clone()   

      throws CloneNotSupportedException {  

    return super。clone();  

  }  

}  



                                                                                    363 


…………………………………………………………Page 365……………………………………………………………

  

// Turn off cloning by throwing the exception:  

class NoMore extends IsCloneable {  

  public Object clone()   

      throws CloneNotSupportedException {  

    throw new CloneNotSupportedException();  

  }  

}  

  

class TryMore extends NoMore {  

  public Object clone()   

      throws CloneNotSupportedException {  

    // Calls NoMore。clone(); throws exception:  

    return super。clone();  

  }  

}  

  

class BackOn extends NoMore {  

  private BackOn duplicate(BackOn b) {  

    // Somehow make a copy of b  

    // and return that copy。 This is a dummy  

    // copy; just to make the point:  

    return new BackOn();  

  }  

  public Object clone() {  

    // Doesn't call NoMore。clone():  

    return duplicate(this);  

  }  

}  

  

// Can't inherit from this; so can't override  

// the clone method like in BackOn:  

final class ReallyNoMore extends NoMore {}  

  

public class CheckCloneable {  

  static Ordinary tryToClone(Ordinary ord) {  

    String id = ord。getClass()。getName();  

    Ordinary x = null;  

    if(ord instanceof Cloneable) {  

      try {  

        System。out。println(〃Attempting 〃 + id);  

        x = (Ordinary)((IsCloneable)ord)。clone();  

        System。out。println(〃Cloned 〃 + id);  

      } catch(CloneNotSupportedException e) {  

        System。out。println(  

          〃Could not clone 〃 + id);  

      }  

    }  

    return x;  

  }  

  public static void main(String'' args) {  

    // Upcasting:  



                                                                                             364 


…………………………………………………………Page 366……………………………………………………………

    Ordinary'' ord = {   

      new IsCloneable();  

      new WrongClone();  

      new NoMore();  

      new TryMore();  

      new BackOn();  

      new ReallyNoMore();  

    };  

    Ordinary x = new Ordinary();  

    // This won't pile; since clone() is  

    // protected in Object:  

    //! x = (Ordinary)x。clone();  

    // tryToClone() checks first to see if  

    // a class implements Cloneable:  

    for(int i = 0; i 《 ord。length; i++)  

      tryToClone(ord'i');  

  }  

} ///:~  

  

第一个类Ordinary 代表着大家在本书各处最常见到的类:不支持克隆,但在它正式应用以后,却也不禁止对 

其克隆。但假如有一个指向Ordinary 对象的句柄,而且那个对象可能是从一个更深的衍生类上溯造型来的, 

便不能判断它到底能不能克隆。  

WrongClone 类揭示了实现克隆的一种不正确途径。它确实覆盖了 Object。clone(),并将那个方法设为 

public,但却没有实现Cloneable。所以一旦发出对super。clone()的调用(由于对Object。clone()的一个 

调用造成的),便会无情地掷出CloneNotSupportedException 违例。  

在 IsCloneable 中,大家看到的才是进行克隆的各种正确行动:先覆盖clone(),并实现了 Cloneable。但 

是,这个clone()方法以及本例的另外几个方法并不捕获CloneNotSupportedException 违例,而是任由它通 

过,并传递给调用者。随后,调用者必须用一个try…catch 代码块把它包围起来。在我们自己的clone()方 

法中,通常需要在 clone()内部捕获CloneNotSupportedException 违例,而不是任由它通过。正如大家以后 

会理解的那样,对这个例子来说,让它通过是最正确的做法。  

类NoMore 试图按照Java 设计者打算的那样“关闭”克隆:在衍生类clone()中,我们掷出 

CloneNotSupportedException 违例。TryMore 类中的clone()方法正确地调用 super。clone() ,并解析成 

NoMore。clone(),后者掷出一个违例并禁止克隆。  

但在已被覆盖的clone()方法中,假若程序员不遵守调用 super。clone()的“正确”方法,又会出现什么情况 

呢?在BackOn 中,大家可看到实际会发生什么。这个类用一个独立的方法duplicate()制作当前对象的一个 

副本,并在 clone()内部调用这个方法,而不是调用super。clone()。违例永远不会产生,而且新类是可以克 

隆的。因此,我们不能依赖“掷”出一个违例的方法来防止产生一个可克隆的类。唯一安全的方法在 

ReallyNoMore 中得到了演示,它设为 final,所以不可继承。这意味着假如clone()在 final 类中掷出了一 

个违例,便不能通过继承来进行修改,并可有效地禁止克隆(不能从一个
返回目录 上一页 下一页 回到顶部 1 1
快捷操作: 按键盘上方向键 ← 或 → 可快速上下翻页 按键盘上的 Enter 键可回到本书目录页 按键盘上方向键 ↑ 可回到本页顶部!
温馨提示: 温看小说的同时发表评论,说出自己的看法和其它小伙伴们分享也不错哦!发表书评还可以获得积分和经验奖励,认真写原创书评 被采纳为精评可以获得大量金币、积分和经验奖励哦!