//: 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(); } ///:~
//: 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(); } } } } ///:~
//: 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 -
Inner class methods can access the data from the scope in which they are defined—including data that would otherwise be private.Inner classes can be hidden from other classes in the same package.Anonymous inner classes are handy when you want to define callbacks without writing a lot of code.这是Core Java第七版给的3个原因: 1.内部类可以访问外部类定义的变量(数据),即使是private的也可以。言外之意,你不用内部类去访问也可以,但是你在类的外部访问的话,就需要通过申明对象去调用方法,再访问变量。多少有点不直接和低效。 2.内部类可以对于同一个package的类实现隐藏。为什么要隐藏?原因很多,一个直接的原因就是这个类对于别的类不一定有什么用,所以就在类的内部实现了。 3.匿名内部类对于事件处理很有用,而且不用写很多代码,直接且高效。其实内部类的一个典型特征就是隐藏。之所以隐藏,一个很重要的原因,可以很夸张地说,这个类的作用很有限,不具有很大的公用性,所以就写在一个类的内部,同时还能减少代码量,对于效率也有所提高。
1.“控制框架”。
2.像C++样,实现“变相”的多继承。
这两个说法的啊,但是不理解。
看了《Think in java(Fourth Edition)》,也还是不懂啊~
想要具体化的了解一下。
在ArrayList中,两个Iterator的实现就说明了这种好处,一个是普通的Iterator 一个是ListIterator 两个实现了Iterator接口,都是内部类,而ArrayList却享受到了实现Iterator的好处。
当然,只是内部类众多好处的一个,其他的暂时还没感悟到
实例内部类可以直接访问嵌套类的成员。如果是定义在方法中的局部内部类,还可以访问该方法中的final型的局部变量和final型的方法参数。
静态内部类只能直接访问所嵌套类的静态成员,而不能直接访问所嵌套类的非静态的成员,如果一定要访问,必须通过外部嵌套类的实例访问。
实例内部类不能声明任何static成员;静态内部类中可以声明static成员。
2.对类的封装,隐藏内部类的代码实现。只有通过外部类得到想到的数据。
我就知道这两个。
1 方便。内部类可以访问外部类的所有属性和方法(包括private的)
2 隐藏。便于隐藏某些“专用类”,如某个界面的监听器类,或某些容器的底层数据结构(如HashMap中的Entry)。
这些类只服务于某个特定的类,不需要外部的任何类知道该信息。隐藏能减少不必要的信息量。
3 便捷。如写Swing界面的事件监听,驱动时,可减少其当做外部类编写时的很多参数传递。其实也是方便。
4 效率。减少了类与类之间交互,少创建了一些对象。当然,这种效率的提升时微不足道的,甚至没有也是可能的。
5 某些情况下使程序变得优雅。内部类有好处,但与此对应,缺点貌似更多。只宜在一些特殊的场合应用。
1 难以阅读。类中还有类,就像怀胎的女人,你一眼看去,个头有些大。便知道此中不简单。
2 类与类之间耦合度很高,难以扩展和维护。
光这2条,其实已够被现代OO大师们打入冷宫了。
但它既然存在,肯定还是有其应用价值的。
常用到内部类的地方:小型GUI程序里监听器类,比较器(Comparator),容器底层专用数据结构等等。内部类是一个不小的话题。跟多信息请google.
一个“应用程序框架”是指一个或一系列类,它们专门设计用来解决特定类型的问题。为应用应用程序框架,我们可从一个或多个类继续,并覆盖其中的部分方法。我们在覆盖方法中编写的代码用于定制由那些应用程序框架提供的常规方案,以便解决自己的实际问题。“控制框架”属于应用程序框架的一种非凡类型,受到对事件响应的需要的支配;主要用来响应事件的一个系统叫作“由事件驱动的系统”。在应用程序设计语言中,最重要的问题之一便是“图形用户界面”(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继续的:
//: 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 -
网上说GUI设计方面,内部类确实用的很多。
但不知道为什么要这么设计,仅仅是为了方便,简洁吗?
1.内部类可以访问外部类定义的变量(数据),即使是private的也可以。言外之意,你不用内部类去访问也可以,但是你在类的外部访问的话,就需要通过申明对象去调用方法,再访问变量。多少有点不直接和低效。
2.内部类可以对于同一个package的类实现隐藏。为什么要隐藏?原因很多,一个直接的原因就是这个类对于别的类不一定有什么用,所以就在类的内部实现了。
3.匿名内部类对于事件处理很有用,而且不用写很多代码,直接且高效。其实内部类的一个典型特征就是隐藏。之所以隐藏,一个很重要的原因,可以很夸张地说,这个类的作用很有限,不具有很大的公用性,所以就写在一个类的内部,同时还能减少代码量,对于效率也有所提高。
之前有做过一些swing的小东东,都还没做过这样的总结!学习了!
够通俗了吧