⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tij0155.html

📁 学习java的经典书籍
💻 HTML
📖 第 1 页 / 共 5 页
字号:
event loop continues. Note that the handle to the 
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>SeparateSubTask</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
is stored so that when you press the 
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>onOff</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
button it can toggle the 
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>runFlag</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
inside the 
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>SeparateSubTask</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
object. That thread (when it looks at the flag) can then start and stop itself.
(This could also have been accomplished by making 
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>SeparateSubTask</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
an inner class.)
</FONT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">The
class 
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>SeparateSubTask</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
is a simple extension of 
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Thread</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
with a constructor (that stores the 
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Counter2</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
handle and then runs the thread by calling 
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>start(&#160;)</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">)
and a 
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>run(&#160;)</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
that essentially contains the code from inside 
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>go(&#160;)</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
in 
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Counter1.java</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">.
Because 
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>SeparateSubTask</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
knows that it holds a handle to a 
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Counter2</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">,
it can reach in and access 
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Counter2</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">&#8217;s
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>TextField</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
when it needs to.
</FONT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">When
you press the 
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>onOff</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
button, you&#8217;ll see a virtually instant response. Of course, the response
isn&#8217;t really instant, not like that of a system that&#8217;s driven by
interrupts. The counter stops only when the thread has the CPU and notices that
the flag has changed.
</FONT><a name="_Ref403700451"></a><P></DIV>
<A NAME="Heading485"></A><H4 ALIGN=LEFT>
Improving
the code with an inner class
</H4>
<DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">As
an aside, look at the coupling that occurs between the 
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>SeparateSubTask</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
and 
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Counter2</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
classes. The 
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>SeparateSubTask</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
is intimately tied to 
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Counter2</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
&#8211; it must keep a handle to its &#8220;parent&#8221; 
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Counter2</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
object so it can call back and manipulate it. And yet the two classes
shouldn&#8217;t really merge together into a single class (although in the next
section you&#8217;ll see that Java provides a way to combine them) because
they&#8217;re doing separate things and are created at different times. They
are tightly connected (what I call a &#8220;<A NAME="Index2464"></A>couplet&#8221;)
and this makes the coding awkward. This is a situation in which an <A NAME="Index2465"></A><A NAME="Index2466"></A><A NAME="Index2467"></A>inner
class can improve the code significantly:
</FONT><P></DIV>

<font color="#990000"><PRE><font color="#009900">//: Counter2i.java</font>
<font color="#009900">// Counter2 using an inner class for the 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> Counter2i <font color="#0000ff">extends</font> Applet {
  <font color="#0000ff">private</font> <font color="#0000ff">class</font> SeparateSubTask <font color="#0000ff">extends</font> Thread {
    <font color="#0000ff">int</font> count = 0;
    <font color="#0000ff">boolean</font> runFlag = <font color="#0000ff">true</font>;
    SeparateSubTask() { start(); }
    <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> {
        sleep(100);
       } <font color="#0000ff">catch</font> (InterruptedException e){}
       <font color="#0000ff">if</font>(runFlag) 
         t.setText(Integer.toString(count++));
      }
    }
  } 
  <font color="#0000ff">private</font> SeparateSubTask sp = <font color="#0000ff">null</font>;
  <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("Toggle"),
    start = <font color="#0000ff">new</font> Button("Start");
  <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("Counter2i");
    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">///:~ </PRE></font></font><DIV ALIGN=LEFT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">This
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>SeparateSubTask</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
name will not collide with the 
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>SeparateSubTask</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
in the previous example even though they&#8217;re in the same directory, since
it&#8217;s hidden as an inner class. You can also see that the <A NAME="Index2468"></A><A NAME="Index2469"></A>inner
class is 
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>private</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">,
which means that its fields and methods can be given default access (except for 
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>run(&#160;)</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">,
which must be 
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>public</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
since it is 
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>public</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
in the base class). The 
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>private
</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">inner
class is not accessible to anyone but 
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Counter2i</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">,
and since the two classes are tightly coupled it&#8217;s convenient to loosen
the access restrictions between them. In 
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>SeparateSubTask</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
you can see that the 
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>invertFlag(&#160;)</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
method has been removed since 
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Counter2i</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
can now directly access 
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>runFlag</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">.</FONT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">Also,
notice that 
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>SeparateSubTask</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">&#8217;s
constructor has been simplified &#8211; now it only starts the thread. The
handle to the 
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Counter2i</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
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 
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>run(&#160;)</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">,
you can see that 
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>t</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
is simply accessed, as if it were a field of 
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>SeparateSubTask</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">.
The 
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>t</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
field in the parent class can now be made 
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>private</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
since 
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>SeparateSubTask</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
can access it without getting any special permission &#8211; and it&#8217;s
always good to make fields &#8220;as private as possible&#8221; so they cannot
be accidentally changed by forces outside your class.
</FONT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">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><P></DIV>
<A NAME="Heading486"></A><H3 ALIGN=LEFT>
Combining
the thread 
<P>with
the main class
<P><A NAME="Index2470"></A></H3>
<DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">In
the example above you can see that the thread class is separate from the
program&#8217;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 
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Frame</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
or 
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Applet</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">,
an interface must be used to paste on the additional functionality. This
interface is called 
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Runnable</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">,
and it contains the same basic method that 
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Thread</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -