友情提示:如果本网页打开太慢或显示不完整,请尝试鼠标右键“刷新”本网页!
Java编程思想第4版[中文版](PDF格式)-第81部分
快捷操作: 按键盘上方向键 ← 或 → 可快速上下翻页 按键盘上的 Enter 键可回到本书目录页 按键盘上方向键 ↑ 可回到本页顶部! 如果本书没有阅读完,想下次继续接着阅读,可使用上方 "收藏到我的浏览器" 功能 和 "加入书签" 功能!
abstract public int getColor();
public Shape(int xVal; int yVal; int dim) {
xPos = xVal;
yPos = yVal;
dimension = dim;
}
public String toString() {
return getClass()。toString() +
〃 color'〃 + getColor() +
〃' xPos'〃 + xPos +
〃' yPos'〃 + yPos +
〃' dim'〃 + dimension + 〃'n〃;
}
public static Shape randomFactory() {
int xVal = r。nextInt() % 100;
328
…………………………………………………………Page 330……………………………………………………………
int yVal = r。nextInt() % 100;
int dim = r。nextInt() % 100;
switch(counter++ % 3) {
default:
case 0: return new Circle(xVal; yVal; dim);
case 1: return new Square(xVal; yVal; dim);
case 2: return new Line(xVal; yVal; dim);
}
}
}
class Circle extends Shape {
private static int color = RED;
public Circle(int xVal; int yVal; int dim) {
super(xVal; yVal; dim);
}
public void setColor(int newColor) {
color = newColor;
}
public int getColor() {
return color;
}
}
class Square extends Shape {
private static int color;
public Square(int xVal; int yVal; int dim) {
super(xVal; yVal; dim);
color = RED;
}
public void setColor(int newColor) {
color = newColor;
}
public int getColor() {
return color;
}
}
class Line extends Shape {
private static int color = RED;
public static void
serializeStaticState(ObjectOutputStream os)
throws IOException {
os。writeInt(color);
}
public static void
deserializeStaticState(ObjectInputStream os)
throws IOException {
color = os。readInt();
}
public Line (int xVal; int yVal; int dim) {
super(xVal; yVal; dim);
329
…………………………………………………………Page 331……………………………………………………………
}
public void setColor(int newColor) {
color = newColor;
}
public int getColor() {
return color;
}
}
public class CADState {
public static void main(String'' args)
throws Exception {
Vector shapeTypes; shapes;
if(args。length == 0) {
shapeTypes = new Vector();
shapes = new Vector();
// Add handles to the class objects:
shapeTypes。addElement(Circle。class);
shapeTypes。addElement(Square。class);
shapeTypes。addElement(Line。class);
// Make some shapes:
for(int i = 0; i 《 10; i++)
shapes。addElement(Shape。randomFactory());
// Set all the static colors to GREEN:
for(int i = 0; i 《 10; i++)
((Shape)shapes。elementAt(i))
。setColor(Shape。GREEN);
// Save the state vector:
ObjectOutputStream out =
new ObjectOutputStream(
new FileOutputStream(〃CADState。out〃));
out。writeObject(shapeTypes);
Line。serializeStaticState(out);
out。writeObject(shapes);
} else { // There's a mand…line argument
ObjectInputStream in =
new ObjectInputStream(
new FileInputStream(args'0'));
// Read in the same order they were written:
shapeTypes = (Vector)in。readObject();
Line。deserializeStaticState(in);
shapes = (Vector)in。readObject();
}
// Display the shapes:
System。out。println(shapes);
}
} ///:~
Shape (几何形状)类“实现了可序列化”(implements Serializable),所以从Shape 继承的任何东西也
都会自动“可序列化”。每个 Shape 都包含了数据,而且每个衍生的Shape 类都包含了一个特殊的 static 字
段,用于决定所有那些类型的 Shape 的颜色(如将一个 static字段置入基础类,结果只会产生一个字段,因
为 static 字段未在衍生类中复制)。可对基础类中的方法进行覆盖处理,以便为不同的类型设置颜色
330
…………………………………………………………Page 332……………………………………………………………
(static 方法不会动态绑定,所以这些都是普通的方法)。每次调用randomFactory()方法时,它都会创建
一个不同的 Shape (Shape 值采用随机值)。
Circle (圆)和Square (矩形)属于对Shape 的直接扩展;唯一的差别是Circle 在定义时会初始化颜色,
而Square 在构建器中初始化。Line (直线)的问题将留到以后讨论。
在main()中,一个Vector 用于容纳Class 对象,而另一个用于容纳形状。若不提供相应的命令行参数,就
会创建 shapeTypes Vector,并添加Class 对象。然后创建 shapes Vector,并添加Shape 对象。接下来,所
有 static color 值都会设成 GREEN,而且所有东西都会序列化到文件 CADState。out。
若提供了一个命令行参数(假设CADState。out),便会打开那个文件,并用它恢复程序的状态。无论在哪种
情况下,结果产生的Shape 的Vector 都会打印出来。下面列出它某一次运行的结果:
》java CADState
'class Circle color'3' xPos'…51' yPos'…99' dim'38'
; class Square color'3' xPos'2' yPos'61' dim'…46'
; class Line color'3' xPos'51' yPos'73' dim'64'
; class Circle color'3' xPos'…70' yPos'1' dim'16'
; class Square color'3' xPos'3' yPos'94' dim'…36'
; class Line color'3' xPos'…84' yPos'…21' dim'…35'
; class Circle color'3' xPos'…75' yPos'…43' dim'22'
; class Square color'3' xPos'81' yPos'30' dim'…45'
; class Line color'3' xPos'…29' yPos'92' dim'17'
; class Circle color'3' xPos'17' yPos'90' dim'…76'
'
》java CADState CADState。out
'class Circle color'1' xPos'…51' yPos'…99' dim'38'
; class Square color'0' xPos'2' yPos'61' dim'…46'
; class Line color'3' xPos'51' yPos'73' dim'64'
; class Circle color'1' xPos'…70' yPos'1' dim'16'
; class Square color'0' xPos'3' yPos'94' dim'…36'
; class Line color'3' xPos'…84' yPos'…21' dim'…35'
; class Circle color'1' xPos'…75' yPos'…43' dim'22'
; class Square color'0' xPos'81' yPos'30' dim'…45'
; class Line color'3' xPos'…29' yPos'92' dim'17'
; class Circle color'1' xPos'17' yPos'90' dim'…76'
'
从中可以看出,xPos,yPos 以及dim 的值都已成功保存和恢复出来。但在获取 static信息时却出现了问
题。所有“3”都已进入,但没有正常地出来。Circle 有一个 1值(定义为 RED),而Square 有一个 0 值
(记住,它们是在构建器里初始化的)。看上去似乎static 根本没有得到初始化!实情正是如此——尽管类
Class 是“可以序列化的”,但却不能按我们希望的工作。所以假如想序列化static值,必须亲自动手。
这正是 Line 中的 serializeStaticState()和 deserializeStaticState()两个 static 方法的用途。可以看
到,这两个方法都是作为存储和恢复进程的一部分明确调用的(注意写入序列化文件和从中读回的顺序不能
改变)。所以为了使CADState。java 正确运行起来,必须采用下述三种方法之一:
(1) 为几何形状添加一个serializeStaticState()和 deserializeStaticState()。
(2) 删除Vector shapeTypes 以及与之有关的所有代码
(3) 在几何形状内添加对新序列化和撤消序列化静态方法的调用
要注意的另一个问题是安全,因为序列化处理也会将private 数据保存下来。若有需要保密的字段,应将其
标记成 transient。但在这之后,必须设计一种安全的信息保存方法。这样一来,一旦需要恢复,就可以重
设那些private 变量。
331
…………………………………………………………Page 333……………………………………………………………
10。10 总结
Java IO 流库能满足我们的许多基本要求:可以通过控制台、文件、内存块甚至因特网(参见第 15章)进行
读写。可以创建新的输入和输出对象类型(通过从 InputStream和 OutputStream 继承)。向一个本来预期为
收到字串的方法传递一个对象时,由于Java 已限制了“自动类型转换”,所以会自动调用toString()方
法。而我们可以重新定义这个 toString(),扩展一个数据流能接纳的对象种类。
在 IO 数据流库的联机文档和设计过程中,仍有些问题没有解决。比如当我们打开一个文件以便输出时,完全
可以指定一旦有人试图覆盖该文件就“掷”出一个违例——有的编程系统允许我们自行指定想打开一个输出
文件,但唯一的前提是它尚不存在。但在 Java 中,似乎必须用一个File 对象来判断某个文件是否存在,因
为假如将其作为FileOutputStream 或者FileWriter 打开,那么肯定会被覆盖。若同时指定文件和目录路
径,File 类设计上的一个缺陷就会暴露出来,因为它会说“不要试图在单个类里做太多的事情”!
IO流库易使我们混淆一些概念。它确实能做许多事情,而且也可以移植。但假如假如事先没有吃透装饰器方
案的概念,那么所有的设计都多少带有一点盲目性质。所以不管学它还是教它,都要特别花一些功夫才行。
而且它并不完整:没有提供对输出格式化的支持,而其他几乎所有语言的 IO包都提供了这方面的支持(这一
点没有在Java 1。1 里得以纠正,它完全错失了改变库设计方案的机会,反而增添了更特殊的一些情况,使复
杂程度进一步提高)。Java 1。1 转到那些尚未替换的 IO 库,而不是增加新库。而且库的设计人员似乎没有
很好地指出哪些特性是不赞成的,哪些是首选的,造成库设计中经常都会出现一些令人恼火的反对消息。
然而,一旦掌握了装饰器方案,并开始在一些较为灵活的环境使用库,就会认识到这种设计的好处。到那个
时候,为此多付出的代码行应该不至于使你觉得太生气。
10。11 练习
(1) 打开一个文本文件,每次读取一行内容。将每行作为一个 String 读入,并将那个String 对象置入一个
Vector 里。按相反的顺序打印出 Vector 中的所有行。
(2) 修改练习 1,使读取那个文件的名字作为一个命令行参数提供。
(3) 修改练习2,又打开一个文本文件,以便将文字写入其中。将 Vector 中的行随同行号一起写入文件。
(4) 修改练习2,强迫Vector 中的所有行都变成大写形式,将结果发给 System。out。
(5) 修改练习2,在文件中查找指定的单词。打印出包含了欲找单词的所有文本行。
(6) 在Blips。java 中复制文件,将其重命名为BlipCheck。java。然后将类Blip2 重命名为BlipCheck (在进
程中将其标记为public)。删除文件中的//!记号,并执行程序。接下来,将BlipCheck 的默认构建器变成
注释信息。运行它,并解释为什么仍然能够工作。
(7) 在Blip3。java 中,将接在“You must do this:”字样后的两行变成注释,然后运行程序。解释得到的
结果为什么会与执行了那两行代码不同。
(8) 转换SortedWordCount。java 程序,以便使用Java 1。1 IO 流。
(9) 根据本章正文的说明修改程序 CADState。java 。
(10) 在第 7 章(中间部分)找到GreenhouseControls。java 示例,它应该由三个文件构成。在
GreenhouseControls。java 中,Restart()内部类有一个硬编码的事件集。请修改这个程序,使其能从一个文
本文件里动态读取事件以及它们的相关时间。
332
…………………………………………………………Page 334……………………………………………………………
第 11 章 运行期类型鉴定
运行期类型鉴定(RTTI )的概念初看非常简单——手上只有基础类型的一个句柄时,利用它判断一个对象的
正确类型。
然而,对RTTI 的需要暴露出了面向对象设计许多有趣(而且经常是令人困惑的)的问题,并把程序的构造问
题正式摆上了桌面。
本章将讨论如何利用Java 在运行期间查找对象和类信息。这主要采取两种形式:一种是“传统”RTTI ,它假
定我们已在编译和运行期拥有所有类型;另一种是 Java1。1 特有的“反射”机制,利用它可在运行期独立查
找类信息。首先讨论“传统”的RTTI,再讨论反射问题。
11。1 对 RTTI 的需要
请考虑下面这个熟悉的类结构例子,它利用了多形性。常规类型是Shape 类
快捷操作: 按键盘上方向键 ← 或 → 可快速上下翻页 按键盘上的 Enter 键可回到本书目录页 按键盘上方向键 ↑ 可回到本页顶部!
温馨提示: 温看小说的同时发表评论,说出自己的看法和其它小伙伴们分享也不错哦!发表书评还可以获得积分和经验奖励,认真写原创书评 被采纳为精评可以获得大量金币、积分和经验奖励哦!