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

📄 tij0120.html

📁 学习java的经典书籍
💻 HTML
📖 第 1 页 / 共 4 页
字号:
<html><body>

<table width="100%"><tr>
<td>
<a href="http://www.bruceeckel.com/javabook.html">Bruce Eckel's Thinking in Java</a>
</td>
<td align="right">
<a href="tij_c.html">Contents</a> | <a href="tij0119.html">Prev</a> | <a href="tij0121.html">Next</a>
</td>
</tr></table>
<hr>

<H2 ALIGN=LEFT>
The
need for RTTI
</H2>
<DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">Consider
the now familiar example of a class hierarchy that uses polymorphism. The
generic type is the base class 
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Shape<A NAME="Index1354"></A><A NAME="Index1355"></A></B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">,
and the specific derived types are 
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Circle</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">,
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Square</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">,
and 
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Triangle</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">This
is a typical class hierarchy diagram, with the base class at the top and the
derived classes growing downward. The normal goal in object-oriented programming<A NAME="Index1356"></A><A NAME="Index1357"></A>
is for the bulk of your code to manipulate handles to the base type (
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Shape</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">,
in this case), so if you decide to extend the program by adding a new class (
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Rhomboid</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">,
derived from 
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Shape</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">,
for example), the bulk of the code is not affected. In this example, the
dynamically bound method in the 
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Shape</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
interface is 
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>draw(&#160;)</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">,
so the intent is for the client programmer to call 
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>draw(&#160;)</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
through a generic 
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Shape</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
handle. 
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>draw(&#160;)</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
is overridden in all of the derived classes, and because it is a dynamically
bound method, the proper behavior will occur even though it is called through a
generic 
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Shape</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
handle. That&#8217;s <A NAME="Index1358"></A>polymorphism.</FONT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">Thus,
you generally create a specific object (
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Circle</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">,
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Square</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">,
or 
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Triangle</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">),
upcast it to a 
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Shape</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
(forgetting the specific type of the object), and use that anonymous 
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Shape
</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">handle
in the rest of the program.
</FONT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">As
a brief review of polymorphism and <A NAME="Index1359"></A>upcasting,
you might code the above example as follows: (See page 
<A HREF=" PAGE#Running_programs">97</A>
if you have trouble executing this program.)
</FONT><P></DIV>

<font color="#990000"><PRE><font color="#009900">//: Shapes.java</font>
<font color="#0000ff">package</font> c11;
<font color="#0000ff">import</font> java.util.*;

<font color="#0000ff">interface</font> Shape {
  <font color="#0000ff">void</font> draw();
}

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

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

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

<font color="#0000ff">public</font> <font color="#0000ff">class</font> Shapes {
  <font color="#0000ff">public</font> <font color="#0000ff">static</font> <font color="#0000ff">void</font> main(String[] args) {
    Vector s = <font color="#0000ff">new</font> Vector();
    s.addElement(<font color="#0000ff">new</font> Circle());
    s.addElement(<font color="#0000ff">new</font> Square());
    s.addElement(<font color="#0000ff">new</font> Triangle());
    Enumeration e = s.elements();
    <font color="#0000ff">while</font>(e.hasMoreElements())
      ((Shape)e.nextElement()).draw();
  }
} <font color="#009900">///:~ </PRE></font></font><DIV ALIGN=LEFT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">The
base class could be coded as an 
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>interface</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">,
an 
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>abstract</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
class, or an ordinary class. Since 
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Shape
</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">has
no concrete members (that is, members with definitions), and it&#8217;s not
intended that you ever create a plain 
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Shape</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
object, the most appropriate and flexible representation is an 
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>interface</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">.
It&#8217;s also cleaner because you don&#8217;t have all those 
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>abstract</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
keywords lying about.
</FONT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">Each
of the derived classes overrides the base-class 
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>draw</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
method so it behaves differently. In 
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>main(&#160;)</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">,
specific types of 
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Shape</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
are created and then added to a 
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Vector</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">.
This is the point at which the upcast occurs because the 
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Vector</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
holds only 
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Object</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">s.
Since everything in Java (with the exception of primitives) is an 
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Object</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">,
a 
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Vector</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
can also hold 
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Shape</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
objects. But during an upcast to 
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Object</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">,</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>
</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">it
also loses any specific information, including the fact that the objects are 
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>shape</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">s.
To the 
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Vector</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">,
they are just 
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Object</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">s.</FONT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">At
the point you fetch an element out of the 
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Vector</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
with 
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>nextElement(&#160;)</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">,
things get a little busy. Since 
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Vector</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
holds only 
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Object</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">s,
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>nextElement(&#160;)</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
naturally produces an 
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Object</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
handle. But we know it&#8217;s really a 
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Shape</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
handle, and we want to send 
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Shape</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
messages to that object. So a <A NAME="Index1360"></A><A NAME="Index1361"></A>cast
to 
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Shape
</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">is
necessary using the traditional &#8220;
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>(Shape)</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">&#8221;
cast. This is the most basic form of RTTI, since in Java all casts are checked
at run-time for correctness. That&#8217;s exactly what RTTI means: at run-time,
the type of an object is identified.
</FONT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">In
this case, the RTTI cast is only partial: the 
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Object</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
is cast to a 
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Shape</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">,
and not all the way to a 
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Circle</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">,
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Square</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">,
or 
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Triangle</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">.
That&#8217;s because the only thing we 
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><I>know</I></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
at this point is that the 
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Vector</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
is full of 
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Shape</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">s.
At compile-time, this is enforced only by your own self-imposed rules, but at
run-time the cast ensures it.
</FONT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">Now
polymorphism takes over and the exact method that&#8217;s called for the 
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Shape</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
is determined by whether the handle is for a 
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Circle</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">,
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Square</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">,
or 
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Triangle</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">.
And in general, this is how it should be; you want the bulk of your code to
know as little as possible about 
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><I>specific</I></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
types of objects, and to just deal with the general representation of a family
of objects (in this case, 
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Shape</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">).
As a result, your code will be easier to write, read, and maintain, and your
designs will be easier to implement, understand, and change. So polymorphism is
the general goal in object-oriented programming.
</FONT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">But
what if you have a special programming problem that&#8217;s easiest to solve if
you know the exact type of a generic handle<A NAME="Index1362"></A><A NAME="Index1363"></A>?
For example, suppose you want to allow your users to highlight all the shapes
of any particular type by turning them purple. This way, they can find all the
triangles on the screen by highlighting them. This is what RTTI accomplishes:
you can ask a handle to a 
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Shape</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
exactly what type it&#8217;s referring to.
</FONT><a name="_Toc375545406"></a><a name="_Toc408018646"></a><a name="_Toc312374135"></a><P></DIV>
<A NAME="Heading354"></A><H3 ALIGN=LEFT>
The
Class object
</H3>
<DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">To

⌨️ 快捷键说明

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