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

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

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


为确切了解其他操作是什么,首先要正确理解 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));  



                                                                                 355 


…………………………………………………………Page 357……………………………………………………………

  }  

  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()并不是个构建器,所以没有办法实现自动克隆。为了克隆,必须由自己明确进 

行。  



12。2。6 克隆合成对象  



试图深层复制合成对象时会遇到一个问题。必须假定成员对象中的clone()方法也能依次对自己的句柄进行 

深层复制,以此类推。这使我们的操作变得复杂。为了能正常实现深层复制,必须对所有类中的代码进行控 

制,或者至少全面掌握深层复制中需要涉及的类,确保它们自己的深层复制能正确进行。  



                                                                                          356 


…………………………………………………………Page 358……………………………………………………………

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

  

//: DeepCopy。java  

// Cloning a posed object  

  

class DepthReading implements Cloneable {  

  private double depth;  

  public DepthReading(double depth) {   

    this。depth = depth;  

  }  

  public Object clone() {  

    Object o = null;  

    try {  

      o = super。clone();  

    } catch (CloneNotSupportedException e) {  

      e。printStackTrace();  

    }  

    return o;  

  }  

}  

  

class TemperatureReading implements Cloneable {  

  private long time;  

  private double temperature;  

  public TemperatureReading(double temperature) {  

    time = System。currentTimeMillis();  

    this。temperature = temperature;  

  }  

  public Object clone() {  

    Object o = null;  

    try {  

      o = super。clone();  

    } catch (CloneNotSupportedException e) {  

      e。printStackTrace();  

    }  

    return o;  

  }  

}  

  

class OceanReading implements Cloneable {  

  private DepthReading depth;  

  private TemperatureReading temperature;  

  public OceanReading(double tdata; double ddata){  

    temperature = new TemperatureReading(tdata);  

    depth = new DepthReading(ddata);  

  }  

  public Object clone() {  

    OceanReading o = null;  

    try {  

      o = (OceanReading)super。clone();  

    } catch (CloneNotSupportedException e) {  

      e。printStackTrace();  



                                                                                             357 


…………………………………………………………Page 359……………………………………………………………

    }  

    // Must clone handles:  

    o。depth = (DepthReading)o。depth。clone();  

    o。temperature =   

      (TemperatureReading)o。temperature。clone();  

    return o; // Upcasts back to Object  

  }  

}  

  

public class DeepCopy {  

  public static void main(String'' args) {  

    OceanReading reading =   

      new OceanReading(33。9; 100。5);  

    // Now clone it:  

    OceanReading r =   

      (OceanReading)reading。clone();  

  }  

} ///:~  

  

DepthReading 和 TemperatureReading 非常相似;它们都只包含了基本数据类型。所以clone()方法能够非常 

简单:调用 super。clone()并返回结果即可。注意两个类使用的clone()代码是完全一致的。  

OceanReading 是由 DepthReading 和 TemperatureReading 对象合并而成的。为了对其进行深层复制,clone() 

必须同时克隆OceanReading 内的句柄。为达到这个目标,super。clone()的结果必须造型成一个 

OceanReading 对象(以便访问depth 和 temperature 句柄)。  



12。2。7 用 Vector 进行深层复制  



下面让我们复习一下本章早些时候提出的Vector 例子。这一次 Int2 类是可以克隆的,所以能对Vector 进行 

深层复制:  

  

//: AddingClone。java  

// You must go through a few gyrations to  

// add cloning to your own class。  

import java。util。*;  

  

class Int2 implements Cloneable {  

  private int i;  

  public Int2(int ii) { i = ii; }  

  public void increment() { i++; }  

  public String toString() {  

    return Integer。toString(i);  

  }  

  public Object clone() {  

    Object o = null;  

    try {  

      o = super。clone();  

    } catch (CloneNotSupportedException e) {  

      System。out。println(〃Int2 can't clone〃);  

    }  

    return o;  

  }  

}  

  



                                                                                             358 


…………………………………………………………Page 360……………………………………………………………

// Once it's cloneable; inheritance  

// doesn't remove cloneability:  

class Int3 extends Int2 {  

  private int j; // Automatically duplicated  

  public Int3(int i) { super(i); }  

}  

  

public class AddingClone {  

  public static void main(String'' args) {  

    Int2 x = new Int2(10);  

    Int2 x2 = (Int2)x。clone();  

    x2。increment();  

    System。out。println(  

      〃x = 〃 + x + 〃; x2 = 〃 + x2);  

    // Anything inherited is also cloneable:  

    Int3 x3 = new Int3(7);  

    x3 = (Int3)x3。clone();  

  

    Vector v = new Vector();  

    for(int i = 0; i 《 10; i++ )  

      v。addElement(new Int2(i));  

    System。out。println(〃v: 〃 + v);  

    Vector v2 = (Vector)v。clone();  

    // Now clone each element:  

    for(int i = 0; i 《 v。size(); i++)  

      v2。setElementAt(  

        ((Int2)v2。elementAt(i))。clone(); i);  

    // Increment all v2's elements:  

    for(Enumeration e = v2。elements();  

        e。hasMoreElements(); )  

      ((Int2)e。nextElement())。increment();  

    // See if it changed v's elements:  

    System。out。println(〃v: 〃 + v);  

    System。out。println(〃v2: 〃 + v2);  

  }  

} ///:~  

  

Int3 自Int2 继承而来,并添加了一个新的基本类型成员 int j。大家也许认为自己需要再次覆盖 clone(), 

以确保j 得到复制,但实情并非如此。将 Int2 的 clone()当作Int3 的 clone()调用时,它会调用 

Object。clone(),判断出当前操作的是 Int3,并复制Int3 内的所有二进制位。只要没有新增需要克隆的句 

柄,对 Object。clone()的一个调用就能完成所有必要的复制——无论clone()是在层次结构多深的一级定义 

的。  

至此,大家可以总结出对Vector 进行深层复制的先决条件:在克隆了Vector 后,必须在其中遍历,并克隆 

由Vector 指向的每个对象。为了对Hashtable (散列表)进行深层复制,也必须采取类似的处理。  

这个例子剩余的部分显示出克隆已实际进行——证据就是在克隆了对象以后,可以自由改变它,而原来那个 

对象不受任何影响。  



12。2。8 通过序列化进行深层复制  



若研究一下第 10 章介绍的那个Java 1。1 对象序列化示例,可能发现若在一个对象序列化以后再撤消对它的 

序列化,或者说进行装配,那么实际经历的正是一个“克隆”的过程。  

那么为什么不用序列化进行深层复制呢?下面这个例子通过计算执行时间对比了这两种方法:  



                                                                                             359 


…………………………………………………………Page 361……………………………………………………………

  

//: pete。java  

import java。io。*;  

  

class Thing1 implements Serializable {}  

class Thing2 implements Serializable {  

  Thing1 o1 = new Thing1();  

}  

  

class Thing3 implements Cloneable {  

  public Object clone() {  

    Object o = null;  

    try {  

      o = super。clone();  

    } catch (CloneNotSupportedException e) {  

      System。out。println(〃Thing3 can't clone〃);  

    }  

    return o;  

  }  

}  

  

class Thing4 implements Cloneable {  

  Thing3 o3 = new Thing3();  

  public Object clone() {  

    Thing4 o = nul l;  

    try {  

      o = (Thing4)super。clone();  

    } catch (CloneNotSupportedException e) {  

      System。out。println(〃Thing4 can't clone〃);  

    }  

    // Clone the field; too:  

    o。o3 = (Thing3)o3。clone();  

    return o;  

  }  

}  

  

public class pete {  

  static final int SIZE = 5000;  

  public static void main(String'' args) {  

    Thing2'' a = new Thing2'SIZE';  

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

      a'i' = new Thing2();  

    Thing4'' b = new Thing4'SIZE';  

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

      b'i' = new Thing4();  

    try {  

      long t1 = System。currentTimeMillis();  

      ByteArrayOutputStream buf =   

        new ByteArrayOutputStream();  

      ObjectOutputStream o =  

        new ObjectOutputStream(buf);  

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



                                                                                             360 


…………………………………………………………Page 362……………………………………………………………

        o。writeObject(a'i');  

      // Now get copies:  

      ObjectInputStream in =  

        new ObjectInputStream(  

          new ByteArrayInputStream(  

            buf。toByteArray()));  

      Thing2'' c = new Thing2'SIZE';  

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

        c'i' = (Thing2)in。readObject();  

      long t2 = System。currentTimeMillis();  

      System。out。println(  

        〃Duplication via serialization: 〃 +  

        (t2 t1) + 〃 Milliseconds〃);  

      // Now try cloning:  

      t1 = System。currentTimeMillis();  

      Thing4'' d = new Thing4'SIZE';  

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

返回目录 上一页 下一页 回到顶部 1 1
快捷操作: 按键盘上方向键 ← 或 → 可快速上下翻页 按键盘上的 Enter 键可回到本书目录页 按键盘上方向键 ↑ 可回到本页顶部!
温馨提示: 温看小说的同时发表评论,说出自己的看法和其它小伙伴们分享也不错哦!发表书评还可以获得积分和经验奖励,认真写原创书评 被采纳为精评可以获得大量金币、积分和经验奖励哦!