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

📄 chap07.htm

📁 java书籍《thinking in java》
💻 HTM
📖 第 1 页 / 共 5 页
字号:
</backtalk:display>
[&nbsp;<a href='http://www.mindview.net/backtalk/CommentServlet?ID=TIJ3_CHAPTER7_I5' 
  target="_blank">Add&nbsp;Comment</a>&nbsp;]

<backtalk:display ID=TIJ3_CHAPTER7_I6>
</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Wouldn&#8217;t it be much nicer if you
could just write a single method that takes the
<A NAME="Index675"></A><A NAME="Index676"></A>base class as its argument, and
not any of the specific derived classes? That is, wouldn&#8217;t it be nice if
you could forget that there are
<A NAME="Index677"></A><A NAME="Index678"></A>derived classes, and write your
code to talk only to the base class?

</backtalk:display>
[&nbsp;<a href='http://www.mindview.net/backtalk/CommentServlet?ID=TIJ3_CHAPTER7_I6' 
  target="_blank">Add&nbsp;Comment</a>&nbsp;]

<backtalk:display ID=TIJ3_CHAPTER7_I7>
</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">That&#8217;s exactly what polymorphism
allows you to do. However, most programmers who come from a procedural
programming background have a bit of trouble with the way polymorphism works.

</backtalk:display>
[&nbsp;<a href='http://www.mindview.net/backtalk/CommentServlet?ID=TIJ3_CHAPTER7_I7' 
  target="_blank">Add&nbsp;Comment</a>&nbsp;]

<backtalk:display ID=TIJ3_CHAPTER7_I8>
</FONT><A NAME="_Toc305593264"></A><A NAME="_Toc305628736"></A><A NAME="_Toc312374041"></A><A NAME="_Toc375545329"></A><A NAME="_Toc481064627"></A><BR></P></DIV>
<A NAME="Heading237"></A><FONT FACE = "Verdana"><H2 ALIGN="LEFT">
The twist</H2></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The difficulty with
<B>Music</B>.<B>java</B> can be seen by running the program. The output is
<B>Wind.play(&#160;)</B>. This is clearly the desired output, but it
doesn&#8217;t seem to make sense that it would work that way. Look at the
<B>tune(&#160;)</B> method:</FONT><BR></P></DIV>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE>  <font color=#0000ff>public</font> <font color=#0000ff>static</font> <font color=#0000ff>void</font> tune(Instrument i) {
    <font color=#009900>// ...</font>
    i.play(Note.MIDDLE_C);
  }</PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">It receives an <B>Instrument</B>
reference. So how can the compiler possibly know that this <B>Instrument</B>
reference points to a <B>Wind</B> in this case and not a <B>Brass </B>or
<B>Stringed</B>? The compiler can&#8217;t. To get a deeper understanding of the
issue, it&#8217;s helpful to examine the subject of <I>binding</I>.

</backtalk:display>
[&nbsp;<a href='http://www.mindview.net/backtalk/CommentServlet?ID=TIJ3_CHAPTER7_I8' 
  target="_blank">Add&nbsp;Comment</a>&nbsp;]

<backtalk:display ID=TIJ3_CHAPTER7_I9>
</FONT><A NAME="_Toc312374042"></A><A NAME="_Toc375545330"></A><A NAME="_Toc481064628"></A><BR></P></DIV>
<A NAME="Heading238"></A><FONT FACE = "Verdana"><H3 ALIGN="LEFT">
Method-call binding<BR><A NAME="Index679"></A><A NAME="Index680"></A></H3></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Connecting a method call to a method body
is called <I>binding</I>. When binding is performed before the program is run
(by the compiler and linker, if there is one), it&#8217;s called <I>early
binding<A NAME="Index681"></A></I>. You might not have heard the term before
because it has never been an option with procedural languages. C compilers have
only one kind of method call, and that&#8217;s early binding.

</backtalk:display>
[&nbsp;<a href='http://www.mindview.net/backtalk/CommentServlet?ID=TIJ3_CHAPTER7_I9' 
  target="_blank">Add&nbsp;Comment</a>&nbsp;]

<backtalk:display ID=TIJ3_CHAPTER7_I10>
</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The confusing part of the above program
revolves around early binding because the compiler cannot know the correct
method to call when it has only an <B>Instrument</B> reference.

</backtalk:display>
[&nbsp;<a href='http://www.mindview.net/backtalk/CommentServlet?ID=TIJ3_CHAPTER7_I10' 
  target="_blank">Add&nbsp;Comment</a>&nbsp;]

<backtalk:display ID=TIJ3_CHAPTER7_I11>
</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The solution is called <I>late
binding<A NAME="Index682"></A><A NAME="Index683"></A></I>, which means that the
binding occurs at run-time based on the type of object. Late binding is also
called <I>dynamic binding<A NAME="Index684"></A><A NAME="Index685"></A></I> or
<I>run-time binding<A NAME="Index686"></A><A NAME="Index687"></A></I>. When a
language implements late binding, there must be some mechanism to determine the
type of the object at run-time and to call the appropriate method. That is, the
compiler still doesn&#8217;t know the object type, but the method-call mechanism
finds out and calls the correct method body. The late-binding mechanism varies
from language to language, but you can imagine that some sort of type
information must be installed in the objects.

</backtalk:display>
[&nbsp;<a href='http://www.mindview.net/backtalk/CommentServlet?ID=TIJ3_CHAPTER7_I11' 
  target="_blank">Add&nbsp;Comment</a>&nbsp;]

<backtalk:display ID=TIJ3_CHAPTER7_I12>
</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">All method binding in Java uses late
binding unless a method has been declared
<A NAME="Index688"></A><A NAME="Index689"></A><B>final</B>. This means that
ordinarily you don&#8217;t need to make any decisions about whether late binding
will occur&#8212;it happens automatically.

</backtalk:display>
[&nbsp;<a href='http://www.mindview.net/backtalk/CommentServlet?ID=TIJ3_CHAPTER7_I12' 
  target="_blank">Add&nbsp;Comment</a>&nbsp;]

<backtalk:display ID=TIJ3_CHAPTER7_I13>
</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Why would you declare a method
<B>final</B>? As noted in the last chapter, it prevents anyone from overriding
that method. Perhaps more important, it effectively &#8220;turns off&#8221;
dynamic binding, or rather it tells the compiler that dynamic binding
isn&#8217;t necessary. This allows the compiler to generate slightly more
efficient code for <B>final</B> method calls. However, in most cases it
won&#8217;t make any overall performance difference in your program, so
it&#8217;s best to only use <B>final</B> as a design decision, and not as an
attempt to improve performance.

</backtalk:display>
[&nbsp;<a href='http://www.mindview.net/backtalk/CommentServlet?ID=TIJ3_CHAPTER7_I13' 
  target="_blank">Add&nbsp;Comment</a>&nbsp;]

<backtalk:display ID=TIJ3_CHAPTER7_I14>
</FONT><A NAME="_Toc375545331"></A><A NAME="_Toc481064629"></A><BR></P></DIV>
<A NAME="Heading239"></A><FONT FACE = "Verdana"><H3 ALIGN="LEFT">
Producing the right behavior</H3></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Once you know that all method binding in
Java happens polymorphically via late binding, you can write your code to talk
to the base class and know that all the derived-class cases will work correctly
using the same code. Or to put it another way, you &#8220;send a message to an
object and let the object figure out the right thing to do.&#8221;

</backtalk:display>
[&nbsp;<a href='http://www.mindview.net/backtalk/CommentServlet?ID=TIJ3_CHAPTER7_I14' 
  target="_blank">Add&nbsp;Comment</a>&nbsp;]

<backtalk:display ID=TIJ3_CHAPTER7_I15>
</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The classic example in OOP is the
&#8220;<A NAME="Index690"></A>shape&#8221; example. This is commonly used
because it is easy to visualize, but unfortunately it can confuse novice
programmers into thinking that OOP is just for graphics programming, which is of
course not the case. 
</backtalk:display>
[&nbsp;<a href='http://www.mindview.net/backtalk/CommentServlet?ID=TIJ3_CHAPTER7_I15' 
  target="_blank">Add&nbsp;Comment</a>&nbsp;]

<backtalk:display ID=TIJ3_CHAPTER7_I16>
</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The shape example has a base class called
<B>Shape </B>and various derived types: <B>Circle</B>, <B>Square</B>,
<B>Triangle</B>, etc. The reason the example works so well is that it&#8217;s
easy to say &#8220;a circle is a type of shape&#8221; and be understood.<B>
</B>The inheritance diagram shows the relationships:</FONT><BR></P></DIV>
<DIV ALIGN="CENTER"><FONT FACE="Georgia"><IMG SRC="TIJ215.gif"></FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The upcast could occur in a statement as
simple as:</FONT><BR></P></DIV>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE>Shape s = <font color=#0000ff>new</font> Circle();</PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Here, a <B>Circle</B> object is created
and the resulting reference is immediately assigned to a <B>Shape</B>, which
would seem to be an error (assigning one type to another); and yet it&#8217;s
fine because a <B>Circle</B> <I>is</I> a <B>Shape</B> by inheritance. So the
compiler agrees with the statement and doesn&#8217;t issue an error message.

</backtalk:display>
[&nbsp;<a href='http://www.mindview.net/backtalk/CommentServlet?ID=TIJ3_CHAPTER7_I16' 
  target="_blank">Add&nbsp;Comment</a>&nbsp;]

<backtalk:display ID=TIJ3_CHAPTER7_I17>
</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Suppose you call one of the base-class
methods (that have been overridden in the derived classes):</FONT><BR></P></DIV>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE>s.draw();</PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Again, you might expect that
<B>Shape</B>&#8217;s <B>draw(&#160;)</B> is called because this is, after all, a
<B>Shape</B> reference&#8212;so how could the compiler know to do anything else?
And yet the proper <B>Circle.draw(&#160;)</B> is called because of late binding
(polymorphism). 
</backtalk:display>
[&nbsp;<a href='http://www.mindview.net/backtalk/CommentServlet?ID=TIJ3_CHAPTER7_I17' 
  target="_blank">Add&nbsp;Comment</a>&nbsp;]

<backtalk:display ID=TIJ3_CHAPTER7_I18>
</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The following example puts it a slightly
different way:</FONT><BR></P></DIV>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: c07:Shapes.java</font>
<font color=#009900>// Polymorphism in Java.</font>

<font color=#0000ff>class</font> Shape { 
  <font color=#0000ff>void</font> draw() {}
  <font color=#0000ff>void</font> erase() {} 
}

<font color=#0000ff>class</font> Circle <font color=#0000ff>extends</font> Shape {
  <font color=#0000ff>void</font> draw() { 
    System.out.println(<font color=#004488>"Circle.draw()"</font>); 
  }
  <font color=#0000ff>void</font> erase() { 
    System.out.println(<font color=#004488>"Circle.erase()"</font>); 
  }
}

<font color=#0000ff>class</font> Square <font color=#0000ff>extends</font> Shape {
  <font color=#0000ff>void</font> draw() { 
    System.out.println(<font color=#004488>"Square.draw()"</font>); 
  }
  <font color=#0000ff>void</font> erase() { 
    System.out.println(<font color=#004488>"Square.erase()"</font>); 
  }
}

<font color=#0000ff>class</font> Triangle <font color=#0000ff>extends</font> Shape {
  <font color=#0000ff>void</font> draw() { 
    System.out.println(<font color=#004488>"Triangle.draw()"</font>); 
  }
  <font color=#0000ff>void</font> erase() { 
    System.out.println(<font color=#004488>"Triangle.erase()"</font>);
  }
}

<font color=#0000ff>public</font> <font color=#0000ff>class</font> Shapes {
  <font color=#0000ff>public</font> <font color=#0000ff>static</font> Shape randShape() {
    <font color=#0000ff>switch</font>((<font color=#0000ff>int</font>)(Math.random() * 3)) {
      <font color=#0000ff>default</font>:
      <font color=#0000ff>case</font> 0: <font color=#0000ff>return</font> <font color=#0000ff>new</font> Circle();
      <font color=#0000ff>case</font> 1: <font color=#0000ff>return</font> <font color=#0000ff>new</font> Square();
      <font color=#0000ff>case</font> 2: <font color=#0000ff>return</font> <font color=#0000ff>new</font> Triangle();
    }
  }
  <font color=#0000ff>public</font> <font color=#0000ff>static</font> <font color=#0000ff>void</font> main(String[] args) {
    Shape[] s = <font color=#0000ff>new</font> Shape[9];
    <font color=#009900>// Fill up the array with shapes:</font>
    <font color=#0000ff>for</font>(<font color=#0000ff>int</font> i = 0; i &lt; s.length; i++)
      s[i] = randShape();
    <font color=#009900>// Make polymorphic method calls:</font>
    <font color=#0000ff>for</font>(<font color=#0000ff>int</font> i = 0; i &lt; s.length; i++)
      s[i].draw();
  }
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The base class <B>Shape</B> establishes
the common interface to anything inherited from <B>Shape</B>&#8212;that is, all
shapes can be drawn and erased. The derived classes override these definitions
to provide unique behavior for each specific type of shape.

</backtalk:display>
[&nbsp;<a href='http://www.mindview.net/backtalk/CommentServlet?ID=TIJ3_CHAPTER7_I18' 
  target="_blank">Add&nbsp;Comment</a>&nbsp;]

<backtalk:display ID=TIJ3_CHAPTER7_I19>
</FONT><BR></P></DIV>

⌨️ 快捷键说明

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