日期:2011-03-22 16:17:00 来源:本站整理
为什么要用内部类:掌握框架[Java编程]
本文“为什么要用内部类:掌握框架[Java编程]”是由七道奇为您精心收集,来源于网络转载,文章版权归文章作者所有,本站不对其观点以及内容做任何评价,请读者自行判断,以下是其具体内容:
到目前为止,大家已接触了对内部类的运作举行描写的大量语法与概念.但这些并不能真正阐明内部类存在的缘由.为什么Sun要如此麻烦地在Java 1.1里增添这样的一种基本语言特点呢?答案就在于我们在这里要学习的“掌握框架”.
一个“利用程序框架”是指一个或一系列类,它们专门计划用来办理特定范例的问题.为利用利用程序框架,我们可从一个或多个类担当,并覆盖此中的部份办法.我们在覆盖办法中编写的代码用于定制由那些利用程序框架供应的通例筹划,以便办理自己的实际问题.“掌握框架”属于利用程序框架的一种特别范例,遭到对事件呼应的需求的支配;主要用来呼应事件的一个系统叫作“由事件驱动的系统”.在利用程序计划语言中,最重要的问题之一就是“图形用户界面”(GUI),它几近美满是由事件驱动的.正如大家会在第13章学习的那样,Java 1.1 AWT属于一种掌握框架,它通过内部类完善地办理了GUI的问题.
为理解内部类若何简化掌握框架的成立与利用,可认为一个掌握框架的工作就是在事件“就绪”今后履行它们.固然“就绪”的意思很多,但在目前这种情形下,我们倒是以计算机时钟为底子.随后,请熟习到针对掌握框架需求掌握的东西,框架内并未包含任何特定的信息.首先,它是一个特别的接口,描写了全部掌握事件.它可以是一个抽象类,而非一个实际的接口.由于默许行为是按照时间掌握的,所以部份实施细节大概包含:
//: Event.java // The common 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: 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()内编写呼应的掌握代码.
④:由于某些特别缘由,这对我来说是一个常常需求办理的、非常风趣的问题;本来的例子在《C++ Inside & Out》一书里也呈现过,但Java供应了一种更令人舒服的办理筹划.
作为利用程序框架的一种典型行为,GreenhouseControls类是从Controller担当的:
注意light(灯光)、water(供水)、thermostat(调温)以及rings都隶属于外部类GreenhouseControls,所以内部类可以毫无阻碍地拜候那些字段.此外,大大都action()办法也触及到某些情势的硬件掌握,这普通都要求发出对非Java代码的调用.//: 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; } public String description() { return "Greenhouse water is on"; } } private class WaterOff extends Event { public WaterOff(long eventTime) { super(eventTime); } public void action() { // Put hardware control code here water = false; } public String description() { return "Greenhouse water is off"; } } private class ThermostatNight extends Event { public ThermostatNight(long eventTime) { super(eventTime); } public void action() { // Put hardware control code here thermostat = "Night"; } public String description() { return "Thermostat on night setting"; } } private class ThermostatDay extends Event { public ThermostatDay(long eventTime) { super(eventTime); } public void action() { // Put hardware control code here thermostat = "Day"; } public String description() { return "Thermostat on day setting"; } } // An example of an action() that inserts a // new one of itself into the event list: private int rings; private class Bell extends Event { public Bell(long eventTime) { super(eventTime); } public void action() { // Ring bell every 2 seconds, rings times: System.out.println("Bing!"); if(--rings > 0) addEvent(new Bell( System.currentTimeMillis() + 2000)); } public String description() { return "Ring bell"; } } private class Restart extends Event { public Restart(long eventTime) { super(eventTime); } public void action() { long tm = System.currentTimeMillis(); // Instead of hard-wiring, you could parse // configuration information from a text // file here: rings = 5; addEvent(new ThermostatNight(tm)); addEvent(new LightOn(tm + 1000)); addEvent(new LightOff(tm + 2000)); addEvent(new WaterOn(tm + 3000)); addEvent(new WaterOff(tm + 8000)); addEvent(new Bell(tm + 9000)); addEvent(new ThermostatDay(tm + 10000)); // Can even add a Restart object! addEvent(new Restart(tm + 20000)); } public String description() { return "Restarting system"; } } public static void main(String[] args) { GreenhouseControls gc = new GreenhouseControls(); long tm = System.currentTimeMillis(); gc.addEvent(gc.new Restart(tm)); gc.run(); } } ///:~
大大都Event类看起来都是类似的,但Bell(铃)和Restart(重启)属于特别情形.Bell会发出响声,若还没有响铃充足的次数,它会在事件列表里增添一个新的Bell对象,所以今后会再度响铃.请注意内部类看起来为什么老是近似于多重担当:Bell拥有Event的全部办法,并且也拥有外部类GreenhouseControls的全部办法.
Restart负责对系统举行初始化,所以会增添全部必要的事件.当然,一种更机动的做法是避免举行“硬编码”,而是从一个文件里读入它们(第10章的一个操练会要求大家改正这个例子,从而到达这个目标).由于Restart()仅仅是另一个Event对象,所以也可以在Restart.action()里增添一个Restart对象,使系统可以按期重启.在main()中,我们需求做的全部事情就是成立一个GreenhouseControls对象,并增添一个Restart对象,令其工作起来.
这个例子应当使大家对内部类的代价有一个越发深化的熟习,分外是在一个掌握框架里利用它们的时刻.此外,在第13章的后半部份,大家还会看到若何巧妙地操纵内部类描写一个图形用户界面的行为.完成那边的学习后,对内部类的熟习将上升到一个前所未有的新高度.
以上是“为什么要用内部类:掌握框架[Java编程]”的内容,如果你对以上该文章内容感兴趣,你可以看看七道奇为您推荐以下文章:
本文地址: | 与您的QQ/BBS好友分享! |
- ·上一篇文章:构建器的调用次序
- ·下一篇文章:java内部类标识符
- ·中查找“为什么要用内部类:掌握框架”更多相关内容
- ·中查找“为什么要用内部类:掌握框架”更多相关内容
评论内容只代表网友观点,与本站立场无关!
评论摘要(共 0 条,得分 0 分,平均 0 分)
查看完整评论