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

第56部分

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

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

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





…………………………………………………………Page 193……………………………………………………………

    public void f() {  

      System。out。println(〃BigEgg2。Yolk。f()〃);  

    }  

  }  

  public BigEgg2() { insertYolk(new Yolk()); }  

  public static void main(String'' args) {  

    Egg2 e2 = new BigEgg2();  

    e2。g();  

  }  

} ///:~  

  

现在,BigEgg2。Yolk 明确地扩展了Egg2。Yolk,而且覆盖了它的方法。方法 insertYolk()允许BigEgg2 将它 

自己的某个Yolk 对象上溯造型至 Egg2 的y 句柄。所以当g()调用y。f()的时候,就会使用f()被覆盖版本。 

输出结果如下:  

Egg2。Yolk()  

New Egg2()  

Egg2。Yolk()  

BigEgg2。Yolk()  

BigEgg2。Yolk。f()  

对Egg2。Yolk()的第二个调用是BigEgg2。Yolk 构建器的基础类构建器调用。调用  

g()的时候,可发现使用的是f()的被覆盖版本。  



7。6。8  内部类标识符  



由于每个类都会生成一个。class 文件,用于容纳与如何创建这个类型的对象有关的所有信息(这种信息产生 

了一个名为 Class 对象的元类),所以大家或许会猜到内部类也必须生成相应的。class 文件,用来容纳与它 

们的Class 对象有关的信息。这些文件或类的名字遵守一种严格的形式:先是封装类的名字,再跟随一个, 

再跟随内部类的名字。例如,由 InheritInner。java创建的。class 文件包括:  

InheritInner。class  

WithInnerInner。class  

WithInner。class  

如果内部类是匿名的,那么编译器会简单地生成数字,把它们作为内部类标识符使用。若内部类嵌套于其他 

内部类中,则它们的名字简单地追加在一个以及外部类标识符的后面。  

这种生成内部名称的方法除了非常简单和直观以外,也非常“健壮”,可适应大多数场合的要求(注释 

③)。由于它是Java 的标准命名机制,所以产生的文件会自动具备“与平台无关”的能力(注意Java 编译 

器会根据情况改变内部类,使其在不同的平台中能正常工作)。  

  

③:但在另一方面,由于“”也是Unix 外壳的一个元字符,所以有时会在列出。class 文件时遇到麻烦。对 

一家以Unix 为基础的公司——Sun——来说,采取这种方案显得有些奇怪。我的猜测是他们根本没有仔细考 

虑这方面的问题,而是认为我们会将全部注意力自然地放在源码文件上。  



7。6。9  为什么要用内部类:控制框架  



到目前为止,大家已接触了对内部类的运作进行描述的大量语法与概念。但这些并不能真正说明内部类存在 

的原因。为什么Sun 要如此麻烦地在Java 1。1 里添加这样的一种基本语言特性呢?答案就在于我们在这里要 

学习的“控制框架”。  

一个“应用程序框架”是指一个或一系列类,它们专门设计用来解决特定类型的问题。为应用应用程序框 

架,我们可从一个或多个类继承,并覆盖其中的部分方法。我们在覆盖方法中编写的代码用于定制由那些应 

用程序框架提供的常规方案,以便解决自己的实际问题。“控制框架”属于应用程序框架的一种特殊类型, 

受到对事件响应的需要的支配;主要用来响应事件的一个系统叫作“由事件驱动的系统”。在应用程序设计 

语言中,最重要的问题之一便是“图形用户界面”(GUI),它几乎完全是由事件驱动的。正如大家会在第 

13章学习的那样,Java 1。1 AWT 属于一种控制框架,它通过内部类完美地解决了GUI 的问题。  

为理解内部类如何简化控制框架的创建与使用,可认为一个控制框架的工作就是在事件“就绪”以后执行它 



                                                                              192 


…………………………………………………………Page 194……………………………………………………………

们。尽管“就绪”的意思很多,但在目前这种情况下,我们却是以计算机时钟为基础。随后,请认识到针对 

控制框架需要控制的东西,框架内并未包含任何特定的信息。首先,它是一个特殊的接口,描述了所有控制 

事件。它可以是一个抽象类,而非一个实际的接口。由于默认行为是根据时间控制的,所以部分实施细节可 

能包括:  

  

//: Event。java  

// The mon methods for any control event  

package c07。controller;  

  

abstract public class Event {  

  private long evtTime;  

  public Event(long eventTime) {  

    evtTime = eventTime;  

  }  

  public boolean ready() {  

    return System。currentTimeMillis() 》= evtTime;  

  }  

  abstract public void action();  

  abstract public String description();  

} ///:~  

  

希望Event (事件)运行的时候,构建器即简单地捕获时间。同时 ready()告诉我们何时该运行它。当然, 

ready()也可以在一个衍生类中被覆盖,将事件建立在除时间以外的其他东西上。  

action()是事件就绪后需要调用的方法,而 description()提供了与事件有关的文字信息。  

下面这个文件包含了实际的控制框架,用于管理和触发事件。第一个类实际只是一个“助手”类,它的职责 

是容纳Event 对象。可用任何适当的集合替换它。而且通过第 8 章的学习,大家会知道另一些集合可简化我 

们的工作,不需要我们编写这些额外的代码:  

  

//: Controller。java  

// Along with Event; the generic  

// framework for all control systems:  

package c07。controller;  

  

// This is just a way to hold Event objects。  

class EventSet {  

  private Event'' events = new Event'100';  

  private int index = 0;  

  private int next = 0;  

  public void add(Event e) {  

    if(index 》= events。length)  

      return; // (In real life; throw exception)  

    events'index++' = e;  

  }  

  public Event getNext() {  

    boolean looped = false;  

    int start = next;  

    do {  

      next = (next + 1) % events。length;  

      // See if it has looped to the beginning:  

      if(start == next) looped = true;  

      // If it loops past start; the list   

      // is empty:  



                                                                                          193 


…………………………………………………………Page 195……………………………………………………………

      if((next == (start + 1) % events。length)  

         && looped)  

        return null;  

    } while(events'next' == null);  

    return events'next';  

  }  

  public void removeCurrent() {  

    events'next' = null;  

  }  

}  

  

public class Controller {  

  private EventSet es = new EventSet();  

  public void addEvent(Event c) { es。add(c); }  

  public void run() {  

    Event e;  

    while((e = es。getNext()) != null) {  

      if(e。ready()) {  

        e。action();  

        System。out。println(e。description());  

        es。removeCurrent();  

      }  

    }  

  }  

} ///:~  

  

EventSet 可容纳 100个事件(若在这里使用来自第 8 章的一个“真实”集合,就不必担心它的最大尺寸,因 

为它会根据情况自动改变大小)。index (索引)在这里用于跟踪下一个可用的空间,而next (下一个)帮 

助我们寻找列表中的下一个事件,了解自己是否已经循环到头。在对 getNext()的调用中,这一点是至关重 

要的,因为一旦运行,Event 对象就会从列表中删去(使用 removeCurrent())。所以getNext()会在列表中 

向前移动时遇到“空洞”。  

注意removeCurrent()并不只是指示一些标志,指出对象不再使用。相反,它将句柄设为null 。这一点是非 

常重要的,因为假如垃圾收集器发现一个句柄仍在使用,就不会清除对象。若认为自己的句柄可能象现在这 

样被挂起,那么最好将其设为 null ,使垃圾收集器能够正常地清除它们。  

Controller 是进行实际工作的地方。它用一个 EventSet 容纳自己的 Event 对象,而且 addEvent()允许我们 

向这个列表加入新事件。但最重要的方法是run()。该方法会在EventSet 中遍历,搜索一个准备运行的 

Event 对象——ready()。对于它发现ready()的每一个对象,都会调用action()方法,打印出 

description(),然后将事件从列表中删去。  

注意在迄今为止的所有设计中,我们仍然不能准确地知道一个“事件”要做什么。这正是整个设计的关键; 

它怎样“将发生变化的东西同没有变化的东西区分开”?或者用我的话来讲,“改变的意图”造成了各类 

Event 对象的不同行动。我们通过创建不同的Event 子类,从而表达出不同的行动。  

这里正是内部类大显身手的地方。它们允许我们做两件事情:  

(1) 在单独一个类里表达一个控制框架应用的全部实施细节,从而完整地封装与那个实施有关的所有东西。 

内部类用于表达多种不同类型的action(),它们用于解决实际的问题。除此以外,后续的例子使用了 

private 内部类,所以实施细节会完全隐藏起来,可以安全地修改。  

(2) 内部类使我们具体的实施变得更加巧妙,因为能方便地访问外部类的任何成员。若不具备这种能力,代 

码看起来就可能没那么使人舒服,最后不得不寻找其他方法解决。  

  

现在要请大家思考控制框架的一种具体实施方式,它设计用来控制温室(Greenhouse)功能(注释④)。每 

个行动都是完全不同的:控制灯光、供水以及温度自动调节的开与关,控制响铃,以及重新启动系统。但控 

制框架的设计宗旨是将不同的代码方便地隔离开。对每种类型的行动,都要继承一个新的Event 内部类,并 

在action() 内编写相应的控制代码。  



                                                                                    194 


…………………………………………………………Page 196……………………………………………………………

  

④:由于某些特殊原因,这对我来说是一个经常需要解决的、非常有趣的问题;原来的例子在《C++ Inside  

& Out》一书里也出现过,但 Java 提供了一种更令人舒适的解决方案。  

  

作为应用程序框架的一种典型行为,GreenhouseControls 类是从 Controller 继承的:  

  

//: GreenhouseControls。java  

// This produces a specific application of the  

// control system; all in a single class。 Inner  

// classes allow you to encapsulate different  

// functionality for each type of event。  

package c07。controller;  

  

public class GreenhouseControls   

    extends Controller {  

  private boolean light = false;  

  private boolean water = false ;  

  private String thermostat = 〃Day〃;  

  private class LightOn extends Event {  

    public LightOn(long eventTime) {  

      super(eventTime);  

    }  

    public void action() {  

      // Put hardware control code here to   

      // physically turn on the light。  

      light = true;  

    }  

    public String description() {  

      return 〃Light is on〃;  

    }  

  }  

  private class LightOff extends Event {  

    public LightOff(long eventTime) {  

      super(eventTime);  

    }  

    public void action() {  

      // Put hardware control code here to   

      // physically turn off the light。  

      light = false;  

    }  

    public String description() {  

      return 〃Light is off〃;  

    }  

  }  

  private class WaterOn extends Event {  

    public WaterOn(long eventTime) {  

      super(eventTime);  

    }  

    public void action() {  

      // Put hardware control code here  

      water = true;  

    }  



                                                                                          195 


…………………………………………………………Page 197……………………………………………………………

    public String description() {  

      return 〃Greenhouse water is on〃;  

    }  

  }  

  private class WaterOff extends Event {  

    public WaterOff(long eventTime) {  

      s

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

你可能喜欢的