Java编程思想第4版[中文版](PDF格式)-第96部分
按键盘上方向键 ← 或 → 可快速上下翻页,按键盘上的 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 只是作为一种用于控制硬件的语言而设计,与因特网并没有丝毫联系。象这样一类面向大众的语
言一样,其意义在于程序员可