chap14.htm
来自「Thinking in Java, 2nd edition」· HTM 代码 · 共 1,236 行 · 第 1/5 页
HTM
1,236 行
calling <B>start( )</B>, and a <B>run( )</B> that essentially contains
the “<B>go( )</B>” code from <B>Counter1.java</B>.
</backtalk:display>
[ <a href='http://www.mindview.net/backtalk/CommentServlet?ID=TIJ3_CHAPTER14_I17'
target="_blank">Add Comment</a> ]
<backtalk:display ID=TIJ3_CHAPTER14_I18>
</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Because <B>SeparateSubTask</B> is an
inner class, it can directly access the <B>JTextField t </B>in <B>Counter2</B>;
you can see this happening inside <B>run( )</B>. The <B>t</B> field in the
outer class is <B>private</B> since <B>SeparateSubTask</B> can access it without
getting any special permission—and it’s always good to make fields
“as <B>private</B> as possible” so they cannot be accidentally
changed by forces outside your class.
</backtalk:display>
[ <a href='http://www.mindview.net/backtalk/CommentServlet?ID=TIJ3_CHAPTER14_I18'
target="_blank">Add Comment</a> ]
<backtalk:display ID=TIJ3_CHAPTER14_I19>
</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">When you press the <B>onOff</B> button it
toggles the <B>runFlag</B> inside the <B>SeparateSubTask</B> object. That thread
(when it looks at the flag) can then start and stop itself. Pressing the
<B>onOff</B> button produces an apparently instant response. Of course, the
response isn’t really instant, not like that of a system that’s
driven by interrupts. The counter stops only when the thread has the CPU and
notices that the flag has changed.
</backtalk:display>
[ <a href='http://www.mindview.net/backtalk/CommentServlet?ID=TIJ3_CHAPTER14_I19'
target="_blank">Add Comment</a> ]
<backtalk:display ID=TIJ3_CHAPTER14_I20>
</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">You can see that the
<A NAME="Index1904"></A><A NAME="Index1905"></A>inner class
<B>SeparateSubTask</B> 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>Counter2</B>, and the two
classes are tightly coupled. 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.
</backtalk:display>
[ <a href='http://www.mindview.net/backtalk/CommentServlet?ID=TIJ3_CHAPTER14_I20'
target="_blank">Add Comment</a> ]
<backtalk:display ID=TIJ3_CHAPTER14_I21>
</FONT><A NAME="_Toc375545475"></A><A NAME="_Toc481064849"></A><BR></P></DIV>
<A NAME="Heading484"></A><FONT FACE = "Verdana"><H3 ALIGN="LEFT">
Combining the thread <BR>with the main class<BR><A NAME="Index1906"></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.
</backtalk:display>
[ <a href='http://www.mindview.net/backtalk/CommentServlet?ID=TIJ3_CHAPTER14_I21'
target="_blank">Add Comment</a> ]
<backtalk:display ID=TIJ3_CHAPTER14_I22>
</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The <I>use</I> 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>//: c14: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=#009900>// <applet code=Counter3 width=300 height=100></font>
<font color=#009900>// </applet></font>
<font color=#0000ff>import</font> javax.swing.*;
<font color=#0000ff>import</font> java.awt.*;
<font color=#0000ff>import</font> java.awt.event.*;
<font color=#0000ff>import</font> com.bruceeckel.swing.*;
<font color=#0000ff>public</font> <font color=#0000ff>class</font> Counter3
<font color=#0000ff>extends</font> JApplet <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> JButton
start = <font color=#0000ff>new</font> JButton(<font color=#004488>"Start"</font>),
onOff = <font color=#0000ff>new</font> JButton(<font color=#004488>"Toggle"</font>);
<font color=#0000ff>private</font> JTextField t = <font color=#0000ff>new</font> JTextField(10);
<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) {
System.err.println(<font color=#004488>"Interrupted"</font>);
}
<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>void</font> init() {
Container cp = getContentPane();
cp.setLayout(<font color=#0000ff>new</font> FlowLayout());
cp.add(t);
start.addActionListener(<font color=#0000ff>new</font> StartL());
cp.add(start);
onOff.addActionListener(<font color=#0000ff>new</font> OnOffL());
cp.add(onOff);
}
<font color=#0000ff>public</font> <font color=#0000ff>static</font> <font color=#0000ff>void</font> main(String[] args) {
Console.run(<font color=#0000ff>new</font> Counter3(), 300, 100);
}
} <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:
</backtalk:display>
[ <a href='http://www.mindview.net/backtalk/CommentServlet?ID=TIJ3_CHAPTER14_I22'
target="_blank">Add Comment</a> ]
<backtalk:display ID=TIJ3_CHAPTER14_I23>
</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="Index1907"></A><A NAME="Index1908"></A><A NAME="Index1909"></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 separate
<B>Thread</B> object as shown above, handing the <B>Runnable</B> object to the
special <B>Thread </B>constructor. You can then call <B>start( )</B> for
that thread:
</backtalk:display>
[ <a href='http://www.mindview.net/backtalk/CommentServlet?ID=TIJ3_CHAPTER14_I23'
target="_blank">Add Comment</a> ]
<backtalk:display ID=TIJ3_CHAPTER14_I24>
</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>.
</backtalk:display>
[ <a href='http://www.mindview.net/backtalk/CommentServlet?ID=TIJ3_CHAPTER14_I24'
target="_blank">Add Comment</a> ]
<backtalk:display ID=TIJ3_CHAPTER14_I25>
</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. However, as you saw in the previous example, this access is just as easy
using an inner
class</FONT><A NAME="fnB70" HREF="#fn70">[70]</A><FONT FACE="Georgia">.
</backtalk:display>
[ <a href='http://www.mindview.net/backtalk/CommentServlet?ID=TIJ3_CHAPTER14_I25'
target="_blank">Add Comment</a> ]
<backtalk:display ID=TIJ3_CHAPTER14_I26>
</FONT><A NAME="_Toc375545476"></A><A NAME="_Toc481064850"></A><BR></P></DIV>
<A NAME="Heading485"></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.
</backtalk:display>
[ <a href='http://www.mindview.net/backtalk/CommentServlet?ID=TIJ3_CHAPTER14_I26'
target="_blank">Add Comment</a> ]
<backtalk:display ID=TIJ3_CHAPTER14_I27>
</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
adds its visual components to the content pane of the outer
object:</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: c14:Counter4.java</font>
<font color=#009900>// By keeping your thread as a distinct class,</font>
<font color=#009900>// you can have as many threads as you want. </font>
<font color=#009900>// <applet code=Counter4 width=200 height=600></font>
<font color=#009900>// <param name=size value="12"></applet></font>
<font color=#0000ff>import</font> javax.swing.*;
<font color=#0000ff>import</font> java.awt.*;
<font color=#0000ff>import</font> java.awt.event.*;
<font color=#0000ff>import</font> com.bruceeckel.swing.*;
<font color=#0000ff>public</font> <font color=#0000ff>class</font> Counter4 <font color=#0000ff>extends</font> JApplet {
<font color=#0000ff>private</font> JButton start = <font color=#0000ff>new</font> JButton(<font color=#004488>"Start"</font>);
<font color=#0000ff>private</font> <font color=#0000ff>boolean</font> started = <font color=#0000ff>false</font>;
<font color=#0000ff>private</font> Ticker[] s;
<font color=#0000ff>private</font> <font color=#0000ff>boolean</font> isApplet = <font color=#0000ff>true</font>;
<font color=#0000ff>private</font> <font color=#0000ff>int</font> size = 12;
<font color=#0000ff>class</font> Ticker <font color=#0000ff>extends</font> Thread {
<font color=#0000ff>private</font> JButton b = <font color=#0000ff>new</font> JButton(<font color=#004488>"Toggle"</font>);
<font color=#0000ff>private</font> JTextField t = <font color=#0000ff>new</font> JTextField(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() {
b.addActionListener(<font color=#0000ff>new</font> ToggleL());
JPanel p = <font color=#0000ff>new</font> JPanel();
p.add(t);
p.add(b);
<font color=#009900>// Calls JApplet.getContentPane().add():</font>
getContentPane().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 + =
减小字号Ctrl + -
显示快捷键?