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

📄 chap12.htm

📁 Thinking in Java, 2nd edition
💻 HTM
📖 第 1 页 / 共 5 页
字号:
</backtalk:display>
[&nbsp;<a href='http://www.mindview.net/backtalk/CommentServlet?ID=TIJ3_CHAPTER12_I17' 
  target="_blank">Add&nbsp;Comment</a>&nbsp;]

<backtalk:display ID=TIJ3_CHAPTER12_I18>
</FONT><A NAME="_Toc481064775"></A><BR></P></DIV>
<A NAME="Heading405"></A><FONT FACE = "Verdana"><H3 ALIGN="LEFT">
Checking before a cast</H3></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">So far, you&#8217;ve seen RTTI forms
including:</FONT><BR></P></DIV>
<OL>
<LI><FONT FACE="Verdana">	</FONT><FONT FACE="Georgia">The classic cast; e.g.,
&#8220;<B>(Shape),</B>&#8221; which uses RTTI to make sure the cast is correct
and throws a <B>ClassCastException</B> if you&#8217;ve performed a bad
cast.</FONT><LI><FONT FACE="Verdana">	</FONT><FONT FACE="Georgia">The
<B>Class</B> object representing the type of your object. The <B>Class</B>
object can be queried for useful run-time information.

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

<backtalk:display ID=TIJ3_CHAPTER12_I19>
</FONT></OL><DIV ALIGN="LEFT"><P><FONT FACE="Georgia">In
C++, the classic cast &#8220;<B>(Shape)</B>&#8221; does <I>not </I>perform RTTI.
It simply tells the compiler to treat the object as the new type. In Java, which
does perform the type check, this cast is often called a &#8220;type safe
downcast<A NAME="Index1489"></A><A NAME="Index1490"></A><A NAME="Index1491"></A>.&#8221;
The reason for the term &#8220;downcast&#8221; is the historical arrangement of
the class hierarchy diagram. If casting a <B>Circle</B> to a <B>Shape</B> is an
upcast, then casting a <B>Shape</B> to a <B>Circle</B> is a downcast. However,
you know a <B>Circle</B> is also a <B>Shape</B>, and the compiler freely allows
an upcast assignment, but you <I>don&#8217;t</I> know that a <B>Shape</B> is
necessarily a <B>Circle</B>, so the compiler doesn&#8217;t allow you to perform
a <A NAME="Index1492"></A><A NAME="Index1493"></A>downcast assignment without
using an explicit cast.  
</backtalk:display>
[&nbsp;<a href='http://www.mindview.net/backtalk/CommentServlet?ID=TIJ3_CHAPTER12_I19' 
  target="_blank">Add&nbsp;Comment</a>&nbsp;]

<backtalk:display ID=TIJ3_CHAPTER12_I20>
</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">There&#8217;s a third form of RTTI in
Java. This is the <A NAME="Index1494"></A><A NAME="Index1495"></A>keyword
<B>instanceof</B> that tells you if an object is an instance of a particular
type. It returns a <B>boolean </B>so you use it in the form of a question, like
this:</FONT><BR></P></DIV>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#0000ff>if</font>(x <font color=#0000ff>instanceof</font> Dog)
  ((Dog)x).bark();</PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The above <B>if</B> statement checks to
see if the object <B>x</B> belongs to the class <B>Dog</B> <I>before</I> casting
<B>x</B> to a <B>Dog</B>. It&#8217;s important to use <B>instanceof</B> before a
downcast when you don&#8217;t have other information that tells you the type of
the object; otherwise you&#8217;ll end up with a
<A NAME="Index1496"></A><A NAME="Index1497"></A><B>ClassCastException</B>.

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

<backtalk:display ID=TIJ3_CHAPTER12_I21>
</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Ordinarily, you might be hunting for one
type (triangles to turn purple, for example), but you can easily tally
<I>all</I> of the objects using <B>instanceof</B>. Suppose you have a family of
<B>Pet</B> classes:</FONT><BR></P></DIV>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: c12:Pets.java</font>
<font color=#0000ff>class</font> Pet {}
<font color=#0000ff>class</font> Dog <font color=#0000ff>extends</font> Pet {}
<font color=#0000ff>class</font> Pug <font color=#0000ff>extends</font> Dog {}
<font color=#0000ff>class</font> Cat <font color=#0000ff>extends</font> Pet {}
<font color=#0000ff>class</font> Rodent <font color=#0000ff>extends</font> Pet {}
<font color=#0000ff>class</font> Gerbil <font color=#0000ff>extends</font> Rodent {}
<font color=#0000ff>class</font> Hamster <font color=#0000ff>extends</font> Rodent {}

<font color=#0000ff>class</font> Counter { <font color=#0000ff>int</font> i; } <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The <B>Counter</B> class is used to keep
track of the number of any particular type of <B>Pet</B>. You could think of it
as an <B>Integer</B> that can be modified.

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

<backtalk:display ID=TIJ3_CHAPTER12_I22>
</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Using <B>instanceof</B>, all the pets can
be counted:</FONT><BR></P></DIV>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: c12:PetCount.java</font>
<font color=#009900>// Using instanceof.</font>
<font color=#0000ff>import</font> java.util.*;

<font color=#0000ff>public</font> <font color=#0000ff>class</font> PetCount {
  <font color=#0000ff>static</font> String[] typenames = {
    <font color=#004488>"Pet"</font>, <font color=#004488>"Dog"</font>, <font color=#004488>"Pug"</font>, <font color=#004488>"Cat"</font>,
    <font color=#004488>"Rodent"</font>, <font color=#004488>"Gerbil"</font>, <font color=#004488>"Hamster"</font>,
  };
  <font color=#009900>// Exceptions thrown out to console:</font>
  <font color=#0000ff>public</font> <font color=#0000ff>static</font> <font color=#0000ff>void</font> main(String[] args) 
  <font color=#0000ff>throws</font> Exception {
    ArrayList pets = <font color=#0000ff>new</font> ArrayList();
    <font color=#0000ff>try</font> {
      Class[] petTypes = {
        Class.forName(<font color=#004488>"Dog"</font>),
        Class.forName(<font color=#004488>"Pug"</font>),
        Class.forName(<font color=#004488>"Cat"</font>),
        Class.forName(<font color=#004488>"Rodent"</font>),
        Class.forName(<font color=#004488>"Gerbil"</font>),
        Class.forName(<font color=#004488>"Hamster"</font>),
      };
      <font color=#0000ff>for</font>(<font color=#0000ff>int</font> i = 0; i &lt; 15; i++)
        pets.add(
          petTypes[
            (<font color=#0000ff>int</font>)(Math.random()*petTypes.length)]
            .newInstance());
    } <font color=#0000ff>catch</font>(InstantiationException e) {
      System.err.println(<font color=#004488>"Cannot instantiate"</font>);
      <font color=#0000ff>throw</font> e;
    } <font color=#0000ff>catch</font>(IllegalAccessException e) {
      System.err.println(<font color=#004488>"Cannot access"</font>);
      <font color=#0000ff>throw</font> e;
    } <font color=#0000ff>catch</font>(ClassNotFoundException e) {
      System.err.println(<font color=#004488>"Cannot find class"</font>);
      <font color=#0000ff>throw</font> e;
    }
    HashMap h = <font color=#0000ff>new</font> HashMap();
    <font color=#0000ff>for</font>(<font color=#0000ff>int</font> i = 0; i &lt; typenames.length; i++)
      h.put(typenames[i], <font color=#0000ff>new</font> Counter());
    <font color=#0000ff>for</font>(<font color=#0000ff>int</font> i = 0; i &lt; pets.size(); i++) {
      Object o = pets.get(i);
      <font color=#0000ff>if</font>(o <font color=#0000ff>instanceof</font> Pet)
        ((Counter)h.get(<font color=#004488>"Pet"</font>)).i++;
      <font color=#0000ff>if</font>(o <font color=#0000ff>instanceof</font> Dog)
        ((Counter)h.get(<font color=#004488>"Dog"</font>)).i++;
      <font color=#0000ff>if</font>(o <font color=#0000ff>instanceof</font> Pug)
        ((Counter)h.get(<font color=#004488>"Pug"</font>)).i++;
      <font color=#0000ff>if</font>(o <font color=#0000ff>instanceof</font> Cat)
        ((Counter)h.get(<font color=#004488>"Cat"</font>)).i++;
      <font color=#0000ff>if</font>(o <font color=#0000ff>instanceof</font> Rodent)
        ((Counter)h.get(<font color=#004488>"Rodent"</font>)).i++;
      <font color=#0000ff>if</font>(o <font color=#0000ff>instanceof</font> Gerbil)
        ((Counter)h.get(<font color=#004488>"Gerbil"</font>)).i++;
      <font color=#0000ff>if</font>(o <font color=#0000ff>instanceof</font> Hamster)
        ((Counter)h.get(<font color=#004488>"Hamster"</font>)).i++;
    }
    <font color=#0000ff>for</font>(<font color=#0000ff>int</font> i = 0; i &lt; pets.size(); i++)
      System.out.println(pets.get(i).getClass());
    <font color=#0000ff>for</font>(<font color=#0000ff>int</font> i = 0; i &lt; typenames.length; i++)
      System.out.println(
        typenames[i] + <font color=#004488>" quantity: "</font> +
        ((Counter)h.get(typenames[i])).i);
  }
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE><DIV ALIGN="LEFT"><P><A NAME="_Toc305593310"></A><A NAME="_Toc305628782"></A><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">There&#8217;s a rather narrow restriction
on <B>instanceof</B>: you can compare it to a named type only, and not to a
<B>Class</B> object. In the example above you might feel that it&#8217;s tedious
to write out all of those <B>instanceof</B> expressions, and you&#8217;re right.
But there is no way to cleverly automate <B>instanceof </B>by creating an
<B>ArrayList</B> of <B>Class</B> objects and comparing it to those instead (stay
tuned&#8212;you&#8217;ll see an alternative). This isn&#8217;t as great a
restriction as you might think, because you&#8217;ll eventually understand that
your design is probably flawed if you end up writing a lot of <B>instanceof</B>
expressions. 
</backtalk:display>
[&nbsp;<a href='http://www.mindview.net/backtalk/CommentServlet?ID=TIJ3_CHAPTER12_I22' 
  target="_blank">Add&nbsp;Comment</a>&nbsp;]

<backtalk:display ID=TIJ3_CHAPTER12_I23>
</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Of course this example is
contrived&#8212;you&#8217;d probably put a <B>static</B> data member in each
type and increment it in the constructor to keep track of the counts. You would
do something like that <I>if</I> you had control of the source code for the
class and could change it. Since this is not always the case, RTTI can come in
handy. 
</backtalk:display>
[&nbsp;<a href='http://www.mindview.net/backtalk/CommentServlet?ID=TIJ3_CHAPTER12_I23' 
  target="_blank">Add&nbsp;Comment</a>&nbsp;]

<backtalk:display ID=TIJ3_CHAPTER12_I24>
</FONT><BR></P></DIV>
<A NAME="Heading406"></A><FONT FACE = "Verdana"><H4 ALIGN="LEFT">
Using class literals</H4></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">It&#8217;s interesting to see how the
<B>PetCount.java</B> example can be rewritten using class
literals<A NAME="Index1498"></A><A NAME="Index1499"></A>. The result is cleaner
in many ways:</FONT><BR></P></DIV>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: c12:PetCount2.java</font>
<font color=#009900>// Using class literals.</font>
<font color=#0000ff>import</font> java.util.*;

<font color=#0000ff>public</font> <font color=#0000ff>class</font> PetCount2 {
  <font color=#0000ff>public</font> <font color=#0000ff>static</font> <font color=#0000ff>void</font> main(String[] args) 
  <font color=#0000ff>throws</font> Exception {
    ArrayList pets = <font color=#0000ff>new</font> ArrayList();
    Class[] petTypes = {
      <font color=#009900>// Class literals:</font>
      Pet.<font color=#0000ff>class</font>,
      Dog.<font color=#0000ff>class</font>,
      Pug.<font color=#0000ff>class</font>,
      Cat.<font color=#0000ff>class</font>,
      Rodent.<font color=#0000ff>class</font>,
      Gerbil.<font color=#0000ff>class</font>,
      Hamster.<font color=#0000ff>class</font>,
    };
    <font color=#0000ff>try</font> {
      <font color=#0000ff>for</font>(<font color=#0000ff>int</font> i = 0; i &lt; 15; i++) {
        <font color=#009900>// Offset by one to eliminate Pet.class:</font>
        <font color=#0000ff>int</font> rnd = 1 + (<font color=#0000ff>int</font>)(
          Math.random() * (petTypes.length - 1));
        pets.add(
          petTypes[rnd].newInstance());
      }
    } <font color=#0000ff>catch</font>(InstantiationException e) {
      System.err.println(<font color=#004488>"Cannot instantiate"</font>);
      <font color=#0000ff>throw</font> e;
    } <font color=#0000ff>catch</font>(IllegalAccessException e) {
      System.err.println(<font color=#004488>"Cannot access"</font>);
      <font color=#0000ff>throw</font> e;
    }
    HashMap h = <font color=#0000ff>new</font> HashMap();
    <font color=#0000ff>for</font>(<font color=#0000ff>int</font> i = 0; i &lt; petTypes.length; i++)
      h.put(petTypes[i].toString(),
        <font color=#0000ff>new</font> Counter());
    <font color=#0000ff>for</font>(<font color=#0000ff>int</font> i = 0; i &lt; pets.size(); i++) {
      Object o = pets.get(i);
      <font color=#0000ff>if</font>(o <font color=#0000ff>instanceof</font> Pet)
        ((Counter)h.get(<font color=#004488>"class Pet"</font>)).i++;
      <font color=#0000ff>if</font>(o <font color=#0000ff>instanceof</font> Dog)
        ((Counter)h.get(<font color=#004488>"class Dog"</font>)).i++;
      <font color=#0000ff>if</font>(o <font color=#0000ff>instanceof</font> Pug)
        ((Counter)h.get(<font color=#004488>"class Pug"</font>)).i++;
      <font color=#0000ff>if</font>(o <font color=#0000ff>instanceof</font> Cat)
        ((Counter)h.get(<font color=#004488>"class Cat"</font>)).i++;
      <font color=#0000ff>if</font>(o <font color=#0000ff>instanceof</font> Rodent)
        ((Counter)h.get(<font color=#004488>"class Rodent"</font>)).i++;
      <font color=#0000ff>if</font>(o <font color=#0000ff>instanceof</font> Gerbil)
        ((Counter)h.get(<font color=#004488>"class Gerbil"</font>)).i++;
      <font color=#0000ff>if</font>(o <font color=#0000ff>instanceof</font> Hamster)
        ((Counter)h.get(<font color=#004488>"class Hamster"</font>)).i++;
    }
    <font color=#0000ff>for</font>(<font color=#0000ff>int</font> i = 0; i &lt; pets.size(); i++)
      System.out.println(pets.get(i).getClass());
    Iterator keys = h.keySet().iterator();
    <font color=#0000ff>while</font>(keys.hasNext()) {
      String nm = (String)keys.next();

⌨️ 快捷键说明

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