📄 chapter14.html
字号:
<font color=#0000ff>private</font> TextField t = <font color=#0000ff>new</font> TextField(10);
<font color=#0000ff>private</font> Button
onOff = <font color=#0000ff>new</font> Button(<font color=#004488>"Toggle"</font>),
start = <font color=#0000ff>new</font> Button(<font color=#004488>"Start"</font>);
<font color=#0000ff>public</font> <font color=#0000ff>void</font> init() {
add(t);
start.addActionListener(<font color=#0000ff>new</font> StartL());
add(start);
onOff.addActionListener(<font color=#0000ff>new</font> OnOffL());
add(onOff);
}
<font color=#0000ff>class</font> StartL <font color=#0000ff>implements</font> ActionListener {
<font color=#0000ff>public</font> <font color=#0000ff>void</font> actionPerformed(ActionEvent e) {
<font color=#0000ff>if</font>(sp == <font color=#0000ff>null</font>)
sp = <font color=#0000ff>new</font> SeparateSubTask();
}
}
<font color=#0000ff>class</font> OnOffL <font color=#0000ff>implements</font> ActionListener {
<font color=#0000ff>public</font> <font color=#0000ff>void</font> actionPerformed(ActionEvent e) {
<font color=#0000ff>if</font>(sp != <font color=#0000ff>null</font>)
sp.runFlag = !sp.runFlag; <font color=#009900>// invertFlag();</font>
}
}
<font color=#0000ff>public</font> <font color=#0000ff>static</font> <font color=#0000ff>void</font> main(String[] args) {
Counter2i applet = <font color=#0000ff>new</font> Counter2i();
Frame aFrame = <font color=#0000ff>new</font> Frame(<font color=#004488>"Counter2i"</font>);
aFrame.addWindowListener(
<font color=#0000ff>new</font> WindowAdapter() {
<font color=#0000ff>public</font> <font color=#0000ff>void</font> windowClosing(WindowEvent e) {
System.exit(0);
}
});
aFrame.add(applet, BorderLayout.CENTER);
aFrame.setSize(300,200);
applet.init();
applet.start();
aFrame.setVisible(<font color=#0000ff>true</font>);
}
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">This <B>SeparateSubTask</B> name
will not collide with the <B>SeparateSubTask</B> in the previous example even
though they’re in the same directory, since it’s hidden as an inner
class. You can also see that the
<A NAME="Index2456"></A><A NAME="Index2457"></A>inner class is <B>private</B>,
which means that its fields and methods can be given default access (except for
<B>run( )</B>, which must be <B>public</B> since it is <B>public</B> in the
base class). The <B>private </B>inner class is not accessible to anyone but
<B>Counter2i</B>, and since the two classes are tightly coupled it’s
convenient to loosen the access restrictions between them. In
<B>SeparateSubTask</B> you can see that the <B>invertFlag( )</B> method has
been removed since <B>Counter2i</B> can now directly access
<B>runFlag</B>.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Also, notice that
<B>SeparateSubTask</B>’s constructor has been simplified – now it
only starts the thread. The handle to the <B>Counter2i</B> object is still being
captured as in the previous version, but instead of doing it by hand and
referencing the outer object by hand, the inner class mechanism takes care of it
automatically. In <B>run( )</B>, you can see that <B>t</B> is simply
accessed, as if it were a field of <B>SeparateSubTask</B>. The <B>t</B> field in
the parent class can now be made <B>private</B> since <B>SeparateSubTask</B> can
access it without getting any special permission – and it’s always
good to make fields “as private as possible” so they cannot be
accidentally changed by forces outside your class.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Anytime you notice classes that
appear to have high coupling with each other, consider the coding and
maintenance improvements you might get by using inner
classes.</FONT><A NAME="_Toc375545475"></A><A NAME="_Toc408018748"></A><BR></P></DIV>
<A NAME="Heading485"></A><FONT FACE = "Verdana"><H3 ALIGN="LEFT">
Combining the thread <BR>with the main class<BR><A NAME="Index2458"></A></H3></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">In the example above you can see
that the thread class is separate from the program’s main class. This
makes a lot of sense and is relatively easy to understand. There is, however, an
alternate form that you will often see used that is not so clear but is usually
more concise (which probably accounts for its popularity). This form combines
the main program class with the thread class by making the main program class a
thread. Since for a GUI program the main program class must be inherited from
either <B>Frame</B> or <B>Applet</B>, an interface must be used to paste on the
additional functionality. This interface is called <B>Runnable</B>, and it
contains the same basic method that <B>Thread</B> does. In fact, <B>Thread</B>
also implements <B>Runnable</B>, which specifies only that there be a
<B>run( )</B> method.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The use of the combined
program/thread is not quite so obvious. When you start the program, you create
an object that’s <B>Runnable</B>, but you don’t start the thread.
This must be done explicitly. You can see this in the following program, which
reproduces the functionality of <B>Counter2</B>:</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: Counter3.java</font>
<font color=#009900>// Using the Runnable interface to turn the </font>
<font color=#009900>// main class into a thread.</font>
<font color=#0000ff>import</font> java.awt.*;
<font color=#0000ff>import</font> java.awt.event.*;
<font color=#0000ff>import</font> java.applet.*;
<font color=#0000ff>public</font> <font color=#0000ff>class</font> Counter3
<font color=#0000ff>extends</font> Applet <font color=#0000ff>implements</font> Runnable {
<font color=#0000ff>private</font> <font color=#0000ff>int</font> count = 0;
<font color=#0000ff>private</font> <font color=#0000ff>boolean</font> runFlag = <font color=#0000ff>true</font>;
<font color=#0000ff>private</font> Thread selfThread = <font color=#0000ff>null</font>;
<font color=#0000ff>private</font> Button
onOff = <font color=#0000ff>new</font> Button(<font color=#004488>"Toggle"</font>),
start = <font color=#0000ff>new</font> Button(<font color=#004488>"Start"</font>);
<font color=#0000ff>private</font> TextField t = <font color=#0000ff>new</font> TextField(10);
<font color=#0000ff>public</font> <font color=#0000ff>void</font> init() {
add(t);
start.addActionListener(<font color=#0000ff>new</font> StartL());
add(start);
onOff.addActionListener(<font color=#0000ff>new</font> OnOffL());
add(onOff);
}
<font color=#0000ff>public</font> <font color=#0000ff>void</font> run() {
<font color=#0000ff>while</font> (<font color=#0000ff>true</font>) {
<font color=#0000ff>try</font> {
selfThread.sleep(100);
} <font color=#0000ff>catch</font> (InterruptedException e){}
<font color=#0000ff>if</font>(runFlag)
t.setText(Integer.toString(count++));
}
}
<font color=#0000ff>class</font> StartL <font color=#0000ff>implements</font> ActionListener {
<font color=#0000ff>public</font> <font color=#0000ff>void</font> actionPerformed(ActionEvent e) {
<font color=#0000ff>if</font>(selfThread == <font color=#0000ff>null</font>) {
selfThread = <font color=#0000ff>new</font> Thread(Counter3.<font color=#0000ff>this</font>);
selfThread.start();
}
}
}
<font color=#0000ff>class</font> OnOffL <font color=#0000ff>implements</font> ActionListener {
<font color=#0000ff>public</font> <font color=#0000ff>void</font> actionPerformed(ActionEvent e) {
runFlag = !runFlag;
}
}
<font color=#0000ff>public</font> <font color=#0000ff>static</font> <font color=#0000ff>void</font> main(String[] args) {
Counter3 applet = <font color=#0000ff>new</font> Counter3();
Frame aFrame = <font color=#0000ff>new</font> Frame(<font color=#004488>"Counter3"</font>);
aFrame.addWindowListener(
<font color=#0000ff>new</font> WindowAdapter() {
<font color=#0000ff>public</font> <font color=#0000ff>void</font> windowClosing(WindowEvent e) {
System.exit(0);
}
});
aFrame.add(applet, BorderLayout.CENTER);
aFrame.setSize(300,200);
applet.init();
applet.start();
aFrame.setVisible(<font color=#0000ff>true</font>);
}
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Now the <B>run( )</B> is
inside the class, but it’s still dormant after <B>init( )</B>
completes. When you press the <B>start</B> button, the thread is created (if it
doesn’t already exist) in the somewhat obscure
expression:</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#0000ff>new</font> Thread(Counter3.<font color=#0000ff>this</font>);</PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">When something has a
<A NAME="Index2459"></A><A NAME="Index2460"></A><A NAME="Index2461"></A><B>Runnable</B>
interface, it simply means that it has a <B>run( )</B> method, but
there’s nothing special about that – it doesn’t produce any
innate threading abilities, like those of a class inherited from <B>Thread</B>.
So to produce a thread from a <B>Runnable</B> object, you must create a thread
separately and hand it the <B>Runnable</B> object; there’s a special
constructor for this that takes a <B>Runnable</B> as its argument. You can then
call <B>start( )</B> for that thread:</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE>selfThread.start();</PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">This performs the usual
initialization and then calls <B>run( )</B>.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The convenient aspect about the
<B>Runnable interface</B> is that everything belongs to the same class. If you
need to access something, you simply do it without going through a separate
object. The penalty for this convenience is strict, though – you can have
only a single thread running for that particular object (although you can create
more objects of that type, or create other threads in different
classes).</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Note that the <B>Runnable</B>
interface is not what imposes this restriction. It’s the combination of
<B>Runnable</B> and your main class that does it, since you can have only one
object of your main class per
application.</FONT><A NAME="_Toc375545476"></A><A NAME="_Toc408018749"></A><BR></P></DIV>
<A NAME="Heading486"></A><FONT FACE = "Verdana"><H3 ALIGN="LEFT">
Making many threads</H3></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Consider the creation of many
different threads. You can’t do this with the previous example, so you
must go back to having separate classes inherited from <B>Thread</B> to
encapsulate the <B>run( )</B>. But this is a more general solution and
easier to understand, so while the previous example shows a coding style
you’ll often see, I can’t recommend it for most cases because
it’s just a little bit more confusing and less flexible.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The following example repeats the
form of the examples above with counters and toggle buttons. But now all the
information for a particular counter, including the button and text field, is
inside its own object that is inherited from <B>Thread</B>. All the fields in
<B>Ticker</B> are <B>private</B>, which means that the <B>Ticker</B>
implementation can be changed at will, including the quantity and type of data
components to acquire and display information. When a <B>Ticker</B> object is
created, the constructor requires a handle to an AWT <B>Container,</B> which
<B>Ticker </B>fills with its visual components. This way, if you change the
visual components, the code that uses <B>Ticker</B> doesn’t need to be
modified.</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: Counter4.java</font>
<font color=#009900>// If you separate your thread from the main</font>
<font color=#009900>// class, you can have as many threads as you</font>
<font color=#009900>// want.</font>
<font color=#0000ff>import</font> java.awt.*;
<font color=#0000ff>import</font> java.awt.event.*;
<font color=#0000ff>import</font> java.applet.*;
<font color=#0000ff>class</font> Ticker <font color=#0000ff>extends</font> Thread {
<font color=#0000ff>private</font> Button b = <font color=#0000ff>new</font> Button(<font color=#004488>"Toggle"</font>);
<font color=#0000ff>private</font> TextField t = <font color=#0000ff>new</font> TextField(10);
<font color=#0000ff>private</font> <font color=#0000ff>int</font> count = 0;
<font color=#0000ff>private</font> <font color=#0000ff>boolean</font> runFlag = <font color=#0000ff>true</font>;
<font color=#0000ff>public</font> Ticker(Container c) {
b.addActionListener(<font color=#0000ff>new</font> ToggleL());
Panel p = <font color=#0000ff>new</font> Panel();
p.add(t);
p.add(b);
c.add(p);
}
<font color=#0000ff>class</font> ToggleL <font color=#0000ff>implements</font> ActionListener {
<font color=#0000ff>public</font> <font color=#0000ff>void</font> actionPerformed(ActionEvent e) {
runFlag = !runFlag;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -