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

📄 chapter06.html

📁 java 是一个很好的网络开发环境。由于它是通过解释的方法
💻 HTML
📖 第 1 页 / 共 5 页
字号:
(This is true for both inheritance and composition.)</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">It&#8217;s important to realize
that program development is an incremental process, just like human learning.
You can do as much analysis as you want, but you still won&#8217;t know all the
answers when you set out on a project. You&#8217;ll have much more success
&#8211; and more immediate feedback &#8211; if you start out to
&#8220;grow&#8221; your project as an organic, evolutionary creature, rather
than constructing it all at once like a glass-box skyscraper.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Although inheritance for
experimentation can be a useful technique, at some point after things stabilize
you need to take a new look at your class hierarchy with an eye to collapsing it
into a sensible structure. Remember that underneath it all, inheritance is meant
to express a relationship that says &#8220;This new class is a <I>type of</I>
that old class.&#8221; Your program should not be concerned with pushing bits
around, but instead with creating and manipulating objects of various types to
express a model in the terms that come from the <A NAME="Index494"></A>problem
space.</FONT><A NAME="_Toc305593259"></A><A NAME="_Toc305628731"></A><A NAME="_Toc312374031"></A><A NAME="_Toc375545315"></A><A NAME="_Toc408018518"></A><BR></P></DIV>
<A NAME="Heading192"></A><FONT FACE = "Verdana"><H2 ALIGN="LEFT">
Upcasting<BR><A NAME="Index495"></A></H2></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The most important aspect of
inheritance is not that it provides methods for the new class. It&#8217;s the
relationship expressed between the new class and the base class. This
<A NAME="Index496"></A>relationship can be summarized by saying &#8220;The new
class <I>is a type of</I> the existing class.&#8221; </FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">This description is not just a
fanciful way of explaining inheritance &#8211; it&#8217;s supported directly by
the language. As an example, consider a base class called <B>Instrument</B> that
represents musical instruments and a derived class called <B>Wind</B>. Because
inheritance means that all of the methods in the base class are also available
in the derived class, any message you can send to the base class can also be
sent to the derived class. If the <B>Instrument</B> class has a
<B>play(&#160;)</B> method, so will <B>Wind</B> instruments. This means we can
accurately say that a <B>Wind</B> object is also a type of <B>Instrument</B>.
The following example shows how the compiler supports this
notion:</FONT><BR></P></DIV>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: Wind.java</font>
<font color=#009900>// Inheritance &amp; upcasting</font>
<font color=#0000ff>import</font> java.util.*;

<font color=#0000ff>class</font> Instrument {
  <font color=#0000ff>public</font> <font color=#0000ff>void</font> play() {}
  <font color=#0000ff>static</font> <font color=#0000ff>void</font> tune(Instrument i) {
    <font color=#009900>// ...</font>
    i.play();
  }
}

<font color=#009900>// Wind objects are instruments</font>
<font color=#009900>// because they have the same interface:</font>
<font color=#0000ff>class</font> Wind <font color=#0000ff>extends</font> Instrument {
  <font color=#0000ff>public</font> <font color=#0000ff>static</font> <font color=#0000ff>void</font> main(String[] args) {
    Wind flute = <font color=#0000ff>new</font> Wind();
    Instrument.tune(flute); <font color=#009900>// Upcasting</font>
  }
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">What&#8217;s interesting in this
example is the <B>tune(&#160;)</B> method, which accepts an <B>Instrument</B>
handle. However, in <B>Wind</B>.<B>main(&#160;)</B> the <B>tune(&#160;)</B>
method is called by giving it a <B>Wind</B> handle. Given that Java is
particular about type checking, it seems strange that a method that accepts one
type will readily accept another type, until you realize that a <B>Wind</B>
object is also an <B>Instrument</B> object, and there&#8217;s no method that
<B>tune(&#160;)</B> could call for an <B>Instrument</B> that isn&#8217;t also in
<B>Wind</B>. Inside <B>tune(&#160;)</B>, the code works for <B>Instrument</B>
and anything derived from <B>Instrument</B>, and the act of converting a
<B>Wind</B> handle into an <B>Instrument</B> handle is called
<I>upcasting</I>.</FONT><A NAME="_Toc312374032"></A><A NAME="_Toc375545316"></A><A NAME="_Toc408018519"></A><BR></P></DIV>
<A NAME="Heading193"></A><FONT FACE = "Verdana"><H3 ALIGN="LEFT">
Why &#8220;upcasting&#8221;?</H3></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The reason for the term is
historical and is based on the way class inheritance diagrams
<A NAME="Index497"></A><A NAME="Index498"></A><A NAME="Index499"></A>have
traditionally been drawn with the root at the top of the page, growing downward.
(Of course, you can draw your diagrams any way you find helpful.) The
inheritance diagram for <B>Wind.java</B> is then: </FONT><BR></P></DIV>
<DIV ALIGN="CENTER"><FONT FACE="Georgia"><IMG SRC="Tjava106.gif"></FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Casting from derived to base moves
<I>up</I> on the inheritance diagram, so it&#8217;s commonly referred to as
upcasting. Upcasting is always safe because you&#8217;re going from a more
specific type to a more general type. That is, the derived class is a superset
of the base class. It might contain more methods than the base class, but it
must contain <I>at least</I> the methods in the base class. The only thing that
can occur to the class interface during the upcast is that it can lose methods,
not gain them. This is why the compiler allows upcasting without any explicit
casts or other special notation.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">You can also perform the reverse of
upcasting, called <A NAME="Index500"></A><I>downcasting</I>, but this involves a
dilemma that is the subject of Chapter
11.</FONT><A NAME="_Toc312374033"></A><BR></P></DIV>
<A NAME="Heading194"></A><FONT FACE = "Verdana"><H4 ALIGN="LEFT">
Composition vs. inheritance revisited</H4></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">In object-oriented programming, the
most likely way that you&#8217;ll create and use code is by simply packaging
data and methods together into a class, and using objects of that class.
Occasionally, you&#8217;ll use existing classes to build new classes with
composition. Even less frequently than that you&#8217;ll use inheritance. So
although inheritance gets a lot of emphasis while learning OOP, it doesn&#8217;t
mean that you should use it everywhere you possibly can. On the contrary, you
should use it sparingly, only when it&#8217;s clear that inheritance is useful.
<A NAME="Index501"></A><A NAME="Index502"></A>One of the clearest ways to
determine whether you should use composition or inheritance is to ask whether
you&#8217;ll ever need to upcast from your new class to the base class. If you
must upcast, then inheritance is necessary, but if you don&#8217;t need to
upcast, then you should look closely at whether you need inheritance. The next
chapter (polymorphism) provides one of the most compelling reasons for
upcasting, but if you remember to ask &#8220;Do I need to upcast?&#8221;,
you&#8217;ll have a good tool for deciding between composition and
inheritance.</FONT><A NAME="_Toc305593260"></A><A NAME="_Toc305628732"></A><A NAME="_Toc312374036"></A><A NAME="_Toc375545317"></A><A NAME="_Toc408018520"></A><BR></P></DIV>
<A NAME="Heading195"></A><FONT FACE = "Verdana"><H2 ALIGN="LEFT">
The final keyword</H2></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The
<A NAME="Index503"></A><B>final</B> keyword has slightly different meanings
depending on the context, but in general it says &#8220;This cannot be
changed.&#8221; You might want to prevent changes for two reasons: design or
efficiency. Because these two reasons are quite different, it&#8217;s possible
to misuse the <B>final</B> keyword.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The following sections discuss the
three places where <B>final</B> can be used: for data, methods and for a
class.</FONT><A NAME="_Toc375545318"></A><A NAME="_Toc408018521"></A><BR></P></DIV>
<A NAME="Heading196"></A><FONT FACE = "Verdana"><H3 ALIGN="LEFT">
Final data<BR><A NAME="Index504"></A><A NAME="Index505"></A></H3></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Many programming languages have a
way to tell the compiler that a piece of data is &#8220;constant.&#8221; A
constant is useful for two reasons: </FONT><BR></P></DIV>
<OL>
<LI><FONT FACE="Georgia">	It can be a
<A NAME="Index506"></A><A NAME="Index507"></A><I>compile-time constant</I> that
won&#8217;t ever change.</FONT><LI><FONT FACE="Georgia">	It can be a value
initialized at <A NAME="Index508"></A>run-time that you don&#8217;t want
changed.</FONT></OL><DIV ALIGN="LEFT"><P><FONT FACE="Georgia">In the case of
a compile-time constant the compiler is allowed to &#8220;fold&#8221; the
<A NAME="Index509"></A><A NAME="Index510"></A>constant value into any
calculations in which it&#8217;s used; that is, the calculation can be performed
at compile time, eliminating some run-time overhead. In Java, these sorts of
constants must be <A NAME="Index511"></A>primitives and are expressed using the
<B>final</B> keyword. A value must be given at the time of definition of such a
constant.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">A field that is both
<A NAME="Index512"></A><A NAME="Index513"></A><B>static</B> and <B>final</B> has
only one piece of storage that cannot be changed.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">When using
<A NAME="Index514"></A><A NAME="Index515"></A><A NAME="Index516"></A><B>final</B>
with object handles rather than primitives the meaning gets a bit confusing.
With a primitive, <B>final</B> makes the <I>value</I> a constant, but with an
object handle, <B>final</B> makes the handle a constant. The handle must be
initialized to an object at the point of declaration, and the handle can never
be changed to point to another object. However, the object can be modified; Java
does not provide a way to make any arbitrary object a constant. (You can,
however, write your class so that objects have the effect of being constant.)
This restriction includes arrays, which are also objects.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Here&#8217;s an example that
demonstrates <B>final</B> fields:</FONT><BR></P></DIV>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: FinalData.java</font>
<font color=#009900>// The effect of final on fields</font>

<font color=#0000ff>class</font> Value {
  <font color=#0000ff>int</font> i = 1;
}

<font color=#0000ff>public</font> <font color=#0000ff>class</font> FinalData {
  <font color=#009900>// Can be compile-time constants</font>
  <font color=#0000ff>final</font> <font color=#0000ff>int</font> i1 = 9;
  <font color=#0000ff>static</font> <font color=#0000ff>final</font> <font color=#0000ff>int</font> I2 = 99;
  <font color=#009900>// Typical public constant:</font>
  <font color=#0000ff>public</font> <font color=#0000ff>static</font> <font color=#0000ff>final</font> <font color=#0000ff>int</font> I3 = 39;
  <font color=#009900>// Cannot be compile-time constants:</font>
  <font color=#0000ff>final</font> <font color=#0000ff>int</font> i4 = (<font color=#0000ff>int</font>)(Math.random()*20);
  <font color=#0000ff>static</font> <font color=#0000ff>final</font> <font color=#0000ff>int</font> i5 = (<font color=#0000ff>int</font>)(Math.random()*20);
  
  Value v1 = <font color=#0000ff>new</font> Value();
  <font color=#0000ff>final</font> Value v2 = <font color=#0000ff>new</font> Value();
  <font color=#0000ff>static</font> <font color=#0000ff>final</font> Value v3 = <font color=#0000ff>new</font> Value();
  <font color=#009900>//! final Value v4; // Pre-Java 1.1 Error: </font>
                      <font color=#009900>// no initializer</font>
  <font color=#009900>// Arrays:</font>
  <font color=#0000ff>final</font> <font color=#0000ff>int</font>[] a = { 1, 2, 3, 4, 5, 6 };

  <font color=#0000ff>public</font> <font color=#0000ff>void</font> print(String id) {
    System.out.println(
      id + <font color=#004488>": "</font> + <font color=#004488>"i4 = "</font> + i4 + 
      <font color=#004488>", i5 = "</font> + i5);
  }
  <font color=#0000ff>public</font> <font color=#0000ff>static</font> <font color=#0000ff>void</font> main(String[] args) {
    FinalData fd1 = <font color=#0000ff>new</font> FinalData();
    <font color=#009900>//! fd1.i1++; // Error: can't change value</font>
    fd1.v2.i++; <font color=#009900>// Object isn't constant!</font>
    fd1.v1 = <font color=#0000ff>new</font> Value(); <font color=#009900>// OK -- not final</font>
    <font color=#0000ff>for</font>(<font color=#0000ff>int</font> i = 0; i &lt; fd1.a.length; i++)
      fd1.a[i]++; <font color=#009900>// Object isn't constant!</font>
    <font color=#009900>//! fd1.v2 = new Value(); // Error: Can't </font>
    <font color=#009900>//! fd1.v3 = new Value(); // change handle</font>
    <font color=#009900>//! fd1.a = new int[3];</font>

    fd1.print(<font color=#004488>"fd1"</font>);
    System.out.println(<font color=#004488>"Creating new FinalData"</font>);
    FinalData fd2 = <font color=#0000ff>new</font> FinalData();
    fd1.print(<font color=#004488>"fd1"</font>);
    fd2.print(<font color=#004488>"fd2"</font>);
  }
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Since <B>i1</B> and <B>I2</B> are
<B>final</B> primitives with compile-time values, they can both be used as
compile-time constants and are not different in any important way. <B>I3</B> is
the more typical way you&#8217;ll see such constants defined: <B>public</B> so
they&#8217;re usable outside the package, <B>static</B> to emphasize that
there&#8217;s only one, and <B>final</B> to say that it&#8217;s a constant. Note
that
<A NAME="Index517"></A><A NAME="Index518"></A><A NAME="Index519"></A><B>final
static</B> primitives with constant initial values (that is, compile-time
constants) are named with all capitals by convention. Also note that <B>i5</B>
cannot be known at compile time, so it is not capitalized.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Just because something is
<B>final</B> doesn&#8217;t mean that its value is known at compile-time. This is
demonstrated by initializing <B>i4</B> and <B>i5</B> at run-time using randomly
generated numbers. This portion of the example also shows the difference between
making a <B>final</B> value <B>static</B> or non-<B>static</B>. This difference
shows

⌨️ 快捷键说明

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