📄 chap12.htm
字号:
</backtalk:display>
[ <a href='http://www.mindview.net/backtalk/CommentServlet?ID=TIJ3_CHAPTER12_I17'
target="_blank">Add Comment</a> ]
<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’ve seen RTTI forms
including:</FONT><BR></P></DIV>
<OL>
<LI><FONT FACE="Verdana"> </FONT><FONT FACE="Georgia">The classic cast; e.g.,
“<B>(Shape),</B>” which uses RTTI to make sure the cast is correct
and throws a <B>ClassCastException</B> if you’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>
[ <a href='http://www.mindview.net/backtalk/CommentServlet?ID=TIJ3_CHAPTER12_I18'
target="_blank">Add Comment</a> ]
<backtalk:display ID=TIJ3_CHAPTER12_I19>
</FONT></OL><DIV ALIGN="LEFT"><P><FONT FACE="Georgia">In
C++, the classic cast “<B>(Shape)</B>” 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 “type safe
downcast<A NAME="Index1489"></A><A NAME="Index1490"></A><A NAME="Index1491"></A>.”
The reason for the term “downcast” 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’t</I> know that a <B>Shape</B> is
necessarily a <B>Circle</B>, so the compiler doesn’t allow you to perform
a <A NAME="Index1492"></A><A NAME="Index1493"></A>downcast assignment without
using an explicit cast.
</backtalk:display>
[ <a href='http://www.mindview.net/backtalk/CommentServlet?ID=TIJ3_CHAPTER12_I19'
target="_blank">Add Comment</a> ]
<backtalk:display ID=TIJ3_CHAPTER12_I20>
</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">There’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’s important to use <B>instanceof</B> before a
downcast when you don’t have other information that tells you the type of
the object; otherwise you’ll end up with a
<A NAME="Index1496"></A><A NAME="Index1497"></A><B>ClassCastException</B>.
</backtalk:display>
[ <a href='http://www.mindview.net/backtalk/CommentServlet?ID=TIJ3_CHAPTER12_I20'
target="_blank">Add Comment</a> ]
<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>
[ <a href='http://www.mindview.net/backtalk/CommentServlet?ID=TIJ3_CHAPTER12_I21'
target="_blank">Add Comment</a> ]
<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 < 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 < 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 < 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 < pets.size(); i++)
System.out.println(pets.get(i).getClass());
<font color=#0000ff>for</font>(<font color=#0000ff>int</font> i = 0; i < 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’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’s tedious
to write out all of those <B>instanceof</B> expressions, and you’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—you’ll see an alternative). This isn’t as great a
restriction as you might think, because you’ll eventually understand that
your design is probably flawed if you end up writing a lot of <B>instanceof</B>
expressions.
</backtalk:display>
[ <a href='http://www.mindview.net/backtalk/CommentServlet?ID=TIJ3_CHAPTER12_I22'
target="_blank">Add Comment</a> ]
<backtalk:display ID=TIJ3_CHAPTER12_I23>
</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Of course this example is
contrived—you’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>
[ <a href='http://www.mindview.net/backtalk/CommentServlet?ID=TIJ3_CHAPTER12_I23'
target="_blank">Add Comment</a> ]
<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’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 < 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 < 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 < 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 < 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 + -