So far, you've been exposed to a lot of syntax and concepts that describe the workings of internal classes. But these do not really explain why the inner class exists. Why is sun so troublesome to add such a basic language feature to Java 1.1? The answer lies in the "control framework" we are learning here. An
application framework refers to one or a series of classes that are specifically designed to solve a particular type of problem. To apply the application framework, we can inherit from one or more classes and overwrite some of these methods. The code we write in the overwrite method is used to customize the general scenarios provided by those application frameworks to solve our own practical problems. A "control framework" is a special type of application framework that is dictated by the need to respond to an event; a system that is primarily used to respond to events is called "event-driven systems". One of the most important issues in the application design language is the graphical user interface (GUI), which is almost entirely driven by events. As you will learn in chapter 13th, the Java 1.1 AWT is a control framework that solves the problem of the GUI perfectly through internal classes.
to understand how inner classes simplify the creation and use of control frameworks, it can be assumed that the work of a control framework is to execute them after the event is "ready." Although "ready" means a lot, in this case, we are based on the computer clock. Then, recognize that there is no specific information in the framework for what you need to control for your control framework. First, it is a special interface that describes all of the control events. It can be an abstract class, not an actual interface. Because the default behavior is controlled by time, some of the implementation details may include the following:
: Event.java
//The common methods for the 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 ();
} ///:~
When you want the event to run, the builder simply captures the time. At the same time ready () tells us when to run it. Of course, ready () can also be overridden in a derived class to build events on something other than time.
Action () is a method that needs to be invoked when the event is ready, and description () provides textual information about the event.
The following file contains the actual control framework for managing and triggering events. The first class is actually just an "assistant" class, and its responsibility is to hold the event object. You can replace it with any appropriate collection. and through the 8th chapter of the study, you will know that other collections can simplify our work without requiring us to write these additional code:
: 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[i
ndex++] = e;
Public Event GetNext () {Boolean looped = false;
int start = next;
do {next = (next + 1)% Events.length;
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 can hold 100 events (if you use a "real" collection from chapter 8th here, you don't have to worry about its maximum size because it automatically changes size depending on the situation). The index (indexed) is used to track the next available space, and next helps us look for the next event in the list to see if we've already cycled to the head. This is critical in the invocation of GetNext (), because once it is run, the event object is deleted from the list (using Removecurrent ()). So GetNext () encounters a "hole" as it moves forward in the list.
Note that removecurrent () does not just indicate some flags, indicating that the object is no longer in use. Instead, it sets the handle to NULL. This is important because if the garbage collector finds that a handle is still in use, the object will not be purged. If you think your handle may be suspended as it is now, it is best to set it to null so that the garbage collector can purge them normally.
Controller is where the actual work is done. It accommodates its own event object with a Eventset, and addevent () allows us to add new events to the list. But the most important method is run (). The method iterates through the Eventset and searches for an event object--ready () that is ready to run. For each object that it finds ready (), it invokes the action () method, prints out description (), and then deletes the event from the list.
Note that in all the designs so far, we still don't know exactly what an "event" is going to do. This is the key to the whole design; how does it "separate the changed things from the unchanged?" Or, in my words, the "change of purpose" creates different actions for the various event objects. We express different actions by creating different event subclasses.
This is where the inner category is. They allow us to do two things:
(1) Express the full implementation details of a control framework application in a separate class, thus fully encapsulating everything related to that implementation. An inner class is used to express several different types of action () that are used to solve the actual problem. In addition, the following examples use the private interior class, so the implementation details are completely hidden and can be safely modified.
(2) The inner class makes our specific implementations more ingenious because it is easy to access any member of the external class. Without this ability, the code might look less comfortable and eventually have to find other ways to solve it.
Now consider a specific implementation of the control framework designed to control greenhouse (greenhouse) functions (annotation ④). Each action is completely different: control the light, water and temperature automatically adjust the open and close, control the bell, and reboot the system. But the purpose of the control framework is to easily isolate the different code. For each type of action, inherit a new event inner class and write the appropriate control code within the action ().
④: For some special reasons, this is a very interesting question that I often need to solve; The original example appeared in the book "C + + Inside & Out", but Java provides a more comfortable solution.
As a typical behavior of the application framework, the Greenhousecontrols class is inherited from controller:
: Greenhousecontrols.java//This produces a specific application of the '//control system ', all in ' a single class.
Inner//classes allow 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);
The public void action () {//Put hardware control code is 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);
The public void action () {//Put hardware control code is 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);
The 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);
The 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 action () is inserts a//new one of itself into the event list:private int rings;
Private class Bell extends Event {public Bell (long Eventtime) {super (eventtime);
The 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);
The public void action () {Long TM = System.currenttimemillis (); Instead of Hard-wiring, 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 (); }
} ///:~
Note that light (lighting), water (water supply), thermostat (thermostat) and rings are all subordinate to the external class greenhousecontrols, so the inner classes can access those fields without hindrance. In addition, most action () methods involve some form of hardware control, which typically requires a call to non-Java code.
Most event classes look similar, but Bell (Bell) and restart (reboot) are special cases. Bell makes a noise, and if it hasn't been ringing enough times, it adds a new Bell object to the event list, so it will ring again later. Notice why the inner class always looks like multiple inheritance: Bell owns all the methods of the event, and also owns all the methods of the external class greenhousecontrols.
Restart is responsible for initializing the system so that all necessary events are added. A more flexible approach, of course, is to avoid "hard coding", but to read them from a file (a practice in chapter 10th will require you to revise this example to achieve this goal). Because restart () is just another event object, you can also add a restart object to the Restart.action () to enable the system to restart periodically. In main (), all we need to do is create a Greenhousecontrols object and add a restart object to make it work.
This example should give you a deeper understanding of the value of internal classes, especially when using them in a control framework. In addition, in the second half of chapter 13th, you will also see how to skillfully use internal classes to describe the behavior of a graphical user interface. After completing the study there, the understanding of the inner class will rise to an unprecedented new height.