📄 tij0088.html
字号:
<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="tij0087.html">Prev</a> | <a href="tij0089.html">Next</a>
</td>
</tr></table>
<hr>
<H2 ALIGN=LEFT>
Collections</H2>
<DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">To
summarize what we’ve seen so far, your first, most efficient choice to
hold a group of objects should be an array, and you’re forced into this
choice if you want to hold a group of primitives. In the remainder of the
chapter we’ll look at the more general case, when you don’t know at
the time you’re writing the program how many objects you’re going
to need, or if you need a more sophisticated way to store your objects. Java
provides four types of <A NAME="Index738"></A></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><I>collection
classes
</I></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
to solve this problem: <A NAME="Index739"></A></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Vector</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">,
<A NAME="Index740"></A></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>BitSet</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">,</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>
<A NAME="Index741"></A>Stack</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">,
and <A NAME="Index742"></A></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Hashtable</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">.
Although compared to other languages that provide collections this is a fairly
meager supply, you can nonetheless solve a surprising number of problems using
these tools.
</FONT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">Among
their other characteristics –
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Stack</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">,
for example, implements a LIFO (last-in, first-out) sequence, and
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Hashtable</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
is an <A NAME="Index743"></A></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><I>associative
array
</I></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
that lets you associate any object with any other object – the Java
collection classes will automatically resize themselves. Thus, you can put in
any number of objects and you don’t need to worry about how big to make
the collection while you’re writing the program.
</FONT><a name="_Ref348399494"></a><a name="_Toc375545351"></a><a name="_Toc408018567"></a><P></DIV>
<A NAME="Heading246"></A><H3 ALIGN=LEFT>
Disadvantage:
unknown type
</H3>
<DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">The
“disadvantage” to using the Java collections is that you lose type
information when you put an object into a collection. This happens because,
when the collection was written, the programmer of that collection had no idea
what specific type you wanted to put in the collection, and making the
collection hold only your type would prevent it from being a general-purpose
tool. So instead, the collection holds handles to objects of type
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Object</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">,
which is of course every object in Java, since it’s the root of all the
classes. (Of course, this doesn’t include primitive types, since they
aren’t inherited from anything.) This is a great solution, except for
these reasons:
</FONT><P></DIV>
<OL>
<LI><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"> Since
the type information is thrown away when you put an object handle into a
collection,
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><I>any</I></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
type of object can be put into your collection, even if you mean it to hold
only, say, cats. Someone could just as easily put a dog into the collection.
</FONT><LI><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"> Since
the type information is lost, the only thing the collection knows it holds is a
handle to an
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Object</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">.
You must perform a <A NAME="Index744"></A>cast
to the correct type before you use it.
</FONT></OL><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">On
the up side, Java won’t let you
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><I>misuse</I></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
the objects that you put into a collection. If you throw a dog into a
collection of cats, then go through and try to treat everything in the
collection as a cat, you’ll get an exception when you get to the dog. In
the same vein, if you try to cast the dog handle that you pull out of the cat
collection into a cat, you’ll get an exception at run-time.
</FONT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">Here’s
an example:
</FONT><P></DIV>
<font color="#990000"><PRE><font color="#009900">//: CatsAndDogs.java</font>
<font color="#009900">// Simple collection example (Vector)</font>
<font color="#0000ff">import</font> java.util.*;
<font color="#0000ff">class</font> Cat {
<font color="#0000ff">private</font> <font color="#0000ff">int</font> catNumber;
Cat(<font color="#0000ff">int</font> i) {
catNumber = i;
}
<font color="#0000ff">void</font> print() {
System.out.println("Cat #" + catNumber);
}
}
<font color="#0000ff">class</font> Dog {
<font color="#0000ff">private</font> <font color="#0000ff">int</font> dogNumber;
Dog(<font color="#0000ff">int</font> i) {
dogNumber = i;
}
<font color="#0000ff">void</font> print() {
System.out.println("Dog #" + dogNumber);
}
}
<font color="#0000ff">public</font> <font color="#0000ff">class</font> CatsAndDogs {
<font color="#0000ff">public</font> <font color="#0000ff">static</font> <font color="#0000ff">void</font> main(String[] args) {
Vector cats = <font color="#0000ff">new</font> Vector();
<font color="#0000ff">for</font>(<font color="#0000ff">int</font> i = 0; i < 7; i++)
cats.addElement(<font color="#0000ff">new</font> Cat(i));
<font color="#009900">// Not a problem to add a dog to cats:</font>
cats.addElement(<font color="#0000ff">new</font> Dog(7));
<font color="#0000ff">for</font>(<font color="#0000ff">int</font> i = 0; i < cats.size(); i++)
((Cat)cats.elementAt(i)).print();
<font color="#009900">// Dog is detected only at run-time</font>
}
} <font color="#009900">///:~ </PRE></font></font><DIV ALIGN=LEFT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">You
can see that using a
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Vector</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
is straightforward: create one, put objects in using <A NAME="Index745"></A><A NAME="Index746"></A></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>addElement( ),</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
and later get them out with <A NAME="Index747"></A><A NAME="Index748"></A></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>elementAt( ).</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
(Note that
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Vector</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
has a method <A NAME="Index749"></A><A NAME="Index750"></A></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>size( )</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
to let you know how many elements have been added so you don’t
inadvertently run off the end and cause an exception.)
</FONT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">The
classes
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Cat</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
and
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Dog</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
are distinct – they have nothing in common except that they are
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Object</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">s.
(If you don’t explicitly say what class you’re inheriting from, you
automatically inherit from
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Object.</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">)
The
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Vector</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
class, which comes from
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>java.util</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">,
holds
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Object</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">s,
so not only can you put
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Cat</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
objects into this collection using the
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Vector
</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">method
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>addElement( )</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">,
but you can also add
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Dog</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
objects without complaint at either compile-time or run-time. When you go to
fetch out what you think are
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Cat</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
objects using the
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Vector</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
method
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>elementAt( )</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">,
you get back a handle to an
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Object</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
that you must cast to a
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Cat</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">.
Then you need to surround the entire expression with parentheses to force the
evaluation of the cast before calling the
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>print( )</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
method for
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Cat</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">,
otherwise you’ll get a syntax error. Then, at run-time, when you try to
cast the
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Dog</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
object to a
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Cat</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">,
you’ll get an exception.
</FONT><P></DIV><DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">This
is more than just an annoyance. It’s something that can create some
difficult-to-find bugs. If one part (or several parts) of a program inserts
objects into a collection, and you discover only in a separate part of the
program through an exception that a bad object was placed in the collection,
then you must find out where the bad insert occurred. You do this by code
inspection, which is about the worst debugging tool you have. On the upside,
it’s convenient to start with some standardized collection classes for
programming, despite the scarcity and awkwardness.
</FONT><P></DIV>
<A NAME="Heading247"></A><H4 ALIGN=LEFT>
Sometimes
it works right anyway
</H4>
<DIV ALIGN=LEFT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">It
turns out that in some cases things seem to work correctly without casting back
to your original type. The first case is quite special: the
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>String</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
class has some extra help from the compiler to make it work smoothly. Whenever
the compiler expects a
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>String</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
object and it hasn’t got one, it will automatically call the <A NAME="Index751"></A><A NAME="Index752"></A></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>toString( )</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
method that’s defined in
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>Object</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
and can be overridden by any Java class. This method produces the desired
</FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black"><B>String</B></FONT><FONT FACE="Carmina Md BT" SIZE=3 COLOR="Black">
object, which is then used wherever it was wanted.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -