八宝书库 > 文学其他电子书 > Java编程思想第4版[中文版](PDF格式) >

第96部分

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

小说: Java编程思想第4版[中文版](PDF格式) 字数: 每页4000字

按键盘上方向键 ← 或 → 可快速上下翻页,按键盘上的 Enter 键可回到本书目录页,按键盘上方向键 ↑ 可回到本页顶部!
————未阅读完?加入书签已便下次继续阅读!




  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++)  

        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 只是作为一种用于控制硬件的语言而设计,与因特网并没有丝毫联系。象这样一类面向大众的语 

言一样,其意义在于程序员可

返回目录 上一页 下一页 回到顶部 0 1

你可能喜欢的