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

📄 chapter06.html

📁 java 是一个很好的网络开发环境。由于它是通过解释的方法
💻 HTML
📖 第 1 页 / 共 5 页
字号:
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Everything in this system is some
kind of <B>Shape</B> (which is itself a kind of <B>Object</B> since it&#8217;s
implicitly inherited from the root class). Each class redefines
<B>Shape</B>&#8217;s <B>cleanup(&#160;)</B> method in addition to calling the
base-class version of that method using <B>super</B>. The specific <B>Shape</B>
classes <B>Circle</B>, <B>Triangle</B> and <B>Line</B> all have constructors
that &#8220;draw,&#8221; although any method called during the lifetime of the
object could be responsible for doing something that needs cleanup. Each class
has its own <B>cleanup(&#160;)</B> method to restore non-memory things back to
the way they were before the object existed.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">In <B>main(&#160;)</B>, you can see
two keywords that are new, and won&#8217;t officially be introduced until
Chapter 9: <A NAME="Index468"></A><B>try</B> and
<A NAME="Index469"></A><B>finally</B>. The <B>try</B> keyword indicates that the
block that follows (delimited by curly braces) is a <I>guarded region</I>, which
means that it is given special treatment. One of these special treatments is
that the code in the <B>finally</B> clause following this guarded region is
<I>always</I> executed, no matter how the <B>try</B> block exits. (With
exception handling, it&#8217;s possible to leave a <B>try</B> block in a number
of non-ordinary ways.) Here, the <B>finally</B> clause is saying &#8220;always
call <B>cleanup(&#160;)</B> for <B>x</B>, no matter what happens.&#8221; These
keywords will be explained thoroughly in Chapter 9.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Note that in your cleanup method
you must also pay attention to the calling order for the base-class and
member-object cleanup methods in case one subobject depends on another. In
general, you should follow the same form that is imposed by a C++ compiler on
its destructors: First perform all of the work specific to your class (which
might require that base-class elements still be viable) then call the base-class
cleanup method, as demonstrated here.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">There can be many cases in which
the cleanup issue is not a problem; you just let the garbage collector do the
work. But when you must do it explicitly, diligence and attention is
required.</FONT><A NAME="_Toc312374020"></A><BR></P></DIV>
<A NAME="Heading187"></A><FONT FACE = "Verdana"><H4 ALIGN="LEFT">
Order of garbage collection</H4></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">There&#8217;s not much you can rely
on when it comes to <A NAME="Index470"></A>garbage collection. The garbage
collector might never be called. If it is, it can reclaim objects in any order
it wants. In addition, implementations of the garbage collector in Java
1.0<A NAME="Index471"></A> often don&#8217;t call the
<A NAME="Index472"></A><B>finalize(&#160;)</B> methods. It&#8217;s best to not
rely on garbage collection for anything but memory reclamation. If you want
cleanup to take place, make your own cleanup methods and don&#8217;t rely on
<A NAME="Index473"></A><B>finalize(&#160;).</B> (As mentioned earlier, Java
1.1<A NAME="Index474"></A> can be forced to call all the
finalizers.)</FONT><A NAME="_Toc312374021"></A><A NAME="_Toc375545311"></A><A NAME="_Toc408018514"></A><BR></P></DIV>
<A NAME="Heading188"></A><FONT FACE = "Verdana"><H3 ALIGN="LEFT">
Name hiding</H3></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Only C++ programmers might be
surprised by name hiding, since it works differently in that language.
<A NAME="Index475"></A><A NAME="Index476"></A><A NAME="Index477"></A><A NAME="Index478"></A>If
a Java base class has a method name that&#8217;s overloaded several times,
redefining that method name in the derived class will <I>not </I>hide any of the
base-class versions. Thus overloading works regardless of whether the method was
defined at this level or in a base class:</FONT><BR></P></DIV>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: Hide.java</font>
<font color=#009900>// Overloading a base-class method name</font>
<font color=#009900>// in a derived class does not hide the</font>
<font color=#009900>// base-class versions</font>

<font color=#0000ff>class</font> Homer {
  <font color=#0000ff>char</font> doh(<font color=#0000ff>char</font> c) {
    System.out.println(<font color=#004488>"doh(char)"</font>);
    <font color=#0000ff>return</font> 'd';
  }
  <font color=#0000ff>float</font> doh(<font color=#0000ff>float</font> f) {
    System.out.println(<font color=#004488>"doh(float)"</font>);
    <font color=#0000ff>return</font> 1.0f;
  }
}

<font color=#0000ff>class</font> Milhouse {}

<font color=#0000ff>class</font> Bart <font color=#0000ff>extends</font> Homer {
  <font color=#0000ff>void</font> doh(Milhouse m) {}
}

<font color=#0000ff>class</font> Hide {
  <font color=#0000ff>public</font> <font color=#0000ff>static</font> <font color=#0000ff>void</font> main(String[] args) {
    Bart b = <font color=#0000ff>new</font> Bart();
    b.doh(1); <font color=#009900>// doh(float) used</font>
    b.doh('x');
    b.doh(1.0f);
    b.doh(<font color=#0000ff>new</font> Milhouse());
  }
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">As you&#8217;ll see in the next
chapter, it&#8217;s far more common to override methods of the same name using
exactly the same signature and return type as in the base class. It can be
confusing otherwise (which is why C++ disallows it, to prevent you from making
what is probably a
mistake).</FONT><A NAME="_Toc305593255"></A><A NAME="_Toc305628727"></A><A NAME="_Toc312374023"></A><A NAME="_Toc375545312"></A><A NAME="_Toc408018515"></A><BR></P></DIV>
<A NAME="Heading189"></A><FONT FACE = "Verdana"><H2 ALIGN="LEFT">
Choosing composition <BR>vs.
inheritance<BR><A NAME="Index479"></A><A NAME="Index480"></A></H2></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Both composition and inheritance
allow you to place subobjects<A NAME="Index481"></A> inside your new class. You
might wonder about the difference between the two, and when to choose one over
the other.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Composition is generally used when
you want the features of an existing class inside your new class, but not its
interface. That is, you embed an object so that you can use it to implement
features of your new class, but the user of your new class sees the interface
you&#8217;ve defined rather than the interface from the embedded object. For
this effect, you embed <B>private</B> objects of existing classes inside your
new class. <A NAME="Index482"></A><A NAME="Index483"></A></FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Sometimes it makes sense to allow
the class user to directly access the composition of your new class; that is, to
make the member objects <B>public</B>. The member objects use implementation
hiding themselves, so this is a safe thing to do and when the user knows
you&#8217;re assembling a bunch of parts, it makes the interface easier to
understand. A <B>car</B> object is a good example:</FONT><BR></P></DIV>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: Car.java</font>
<font color=#009900>// Composition with public objects</font>

<font color=#0000ff>class</font> Engine {
  <font color=#0000ff>public</font> <font color=#0000ff>void</font> start() {}
  <font color=#0000ff>public</font> <font color=#0000ff>void</font> rev() {}
  <font color=#0000ff>public</font> <font color=#0000ff>void</font> stop() {}
}

<font color=#0000ff>class</font> Wheel {
  <font color=#0000ff>public</font> <font color=#0000ff>void</font> inflate(<font color=#0000ff>int</font> psi) {}
}

<font color=#0000ff>class</font> Window {
  <font color=#0000ff>public</font> <font color=#0000ff>void</font> rollup() {}
  <font color=#0000ff>public</font> <font color=#0000ff>void</font> rolldown() {}
}

<font color=#0000ff>class</font> Door {
  <font color=#0000ff>public</font> Window window = <font color=#0000ff>new</font> Window();
  <font color=#0000ff>public</font> <font color=#0000ff>void</font> open() {}
  <font color=#0000ff>public</font> <font color=#0000ff>void</font> close() {}
}

<font color=#0000ff>public</font> <font color=#0000ff>class</font> Car {
  <font color=#0000ff>public</font> Engine engine = <font color=#0000ff>new</font> Engine();
  <font color=#0000ff>public</font> Wheel[] wheel = <font color=#0000ff>new</font> Wheel[4];
  <font color=#0000ff>public</font> Door left = <font color=#0000ff>new</font> Door(),
       right = <font color=#0000ff>new</font> Door(); <font color=#009900>// 2-door</font>
  Car() {
    <font color=#0000ff>for</font>(<font color=#0000ff>int</font> i = 0; i &lt; 4; i++)
      wheel[i] = <font color=#0000ff>new</font> Wheel();
  }
  <font color=#0000ff>public</font> <font color=#0000ff>static</font> <font color=#0000ff>void</font> main(String[] args) {
    Car car = <font color=#0000ff>new</font> Car();
    car.left.window.rollup();
    car.wheel[0].inflate(72);
  }
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Because the composition of a car is
part of the analysis of the problem (and not simply part of the underlying
design), making the members public assists the client programmer&#8217;s
understanding of how to use the class and requires less code complexity for the
creator of the class.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><A NAME="Index484"></A><A NAME="Index485"></A><FONT FACE="Georgia">When
you inherit, you take an existing class and make a special version of it. In
general, this means that you&#8217;re taking a general-purpose class and
specializing it for a particular need. With a little thought, you&#8217;ll see
that it would make no sense to compose a car using a vehicle object &#8211; a
car doesn&#8217;t contain a vehicle, it <I>is</I> a vehicle. The
<A NAME="Index486"></A><I>is-a</I> relationship is expressed with inheritance,
and the <A NAME="Index487"></A><I>has-a</I> relationship is expressed with
composition.</FONT><A NAME="_Toc305593256"></A><A NAME="_Toc305628728"></A><A NAME="_Toc312374027"></A><A NAME="_Toc375545313"></A><A NAME="_Toc408018516"></A><BR></P></DIV>
<A NAME="Heading190"></A><FONT FACE = "Verdana"><H2 ALIGN="LEFT">
protected</H2></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Now that you&#8217;ve been
introduced to inheritance, the keyword <B>protected<A NAME="Index488"></A></B>
finally has meaning. In an ideal world, <B>private</B> members would always be
hard-and-fast <B>private</B>, but in real projects there are times when you want
to make something hidden from the world at large and yet allow access for
members of derived classes. The <B>protected</B> keyword is a nod to pragmatism.
It says &#8220;This is <B>private</B> as far as the class user is concerned, but
available to anyone who inherits from this class or anyone else in the same
<B>package</B>.&#8221; That is, <A NAME="Index489"></A><B>protected</B> in Java
is automatically &#8220;friendly.&#8221;</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The best tack to take is to leave
the data members <A NAME="Index490"></A><B>private</B> &#8211; you should always
preserve your right to change the underlying implementation. You can then allow
controlled access to inheritors of your class through
<A NAME="Index491"></A><B>protected </B>methods:</FONT><BR></P></DIV>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: Orc.java</font>
<font color=#009900>// The protected keyword</font>
<font color=#0000ff>import</font> java.util.*;

<font color=#0000ff>class</font> Villain {
  <font color=#0000ff>private</font> <font color=#0000ff>int</font> i;
  <font color=#0000ff>protected</font> <font color=#0000ff>int</font> read() { <font color=#0000ff>return</font> i; }
  <font color=#0000ff>protected</font> <font color=#0000ff>void</font> set(<font color=#0000ff>int</font> ii) { i = ii; }
  <font color=#0000ff>public</font> Villain(<font color=#0000ff>int</font> ii) { i = ii; }
  <font color=#0000ff>public</font> <font color=#0000ff>int</font> value(<font color=#0000ff>int</font> m) { <font color=#0000ff>return</font> m*i; }
}

<font color=#0000ff>public</font> <font color=#0000ff>class</font> Orc <font color=#0000ff>extends</font> Villain {
  <font color=#0000ff>private</font> <font color=#0000ff>int</font> j;
  <font color=#0000ff>public</font> Orc(<font color=#0000ff>int</font> jj) { <font color=#0000ff>super</font>(jj); j = jj; }
  <font color=#0000ff>public</font> <font color=#0000ff>void</font> change(<font color=#0000ff>int</font> x) { set(x); }
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">You can see that
<B>change(&#160;)</B> has access to <B>set(&#160;)</B> because it&#8217;s
<B>protected</B>.</FONT><A NAME="_Toc305593258"></A><A NAME="_Toc305628730"></A><A NAME="_Toc312374030"></A><A NAME="_Toc375545314"></A><A NAME="_Toc408018517"></A><BR></P></DIV>
<A NAME="Heading191"></A><FONT FACE = "Verdana"><H2 ALIGN="LEFT">
Incremental development</H2></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">One of the advantages of
inheritance is that it supports <I>incremental
development<A NAME="Index492"></A><A NAME="Index493"></A></I> by allowing you to
introduce new code without causing bugs in existing code. This also isolates new
bugs to the new code. By inheriting from an existing, functional class and
adding data members and methods (and redefining existing methods), you leave the
existing code &#8211; that someone else might still be using &#8211; untouched
and unbugged. If a bug happens, you know that it&#8217;s in your new code, which
is much shorter and easier to read than if you had modified the body of existing
code.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">It&#8217;s rather amazing how
cleanly the classes are separated. You don&#8217;t even need the source code for
the methods in order to reuse the code. At most, you just import a package.

⌨️ 快捷键说明

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