📄 chapter08.html
字号:
System.out.println(<font color=#004488>"e.length = "</font> + e.length);
<font color=#009900>// Java 1.1 initialization syntax:</font>
e = <font color=#0000ff>new</font> <font color=#0000ff>int</font>[] { 1, 2 };
System.out.println(<font color=#004488>"e.length = "</font> + e.length);
}
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Here’s the output from the
program:</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE>b.length = 5
b[0]=<font color=#0000ff>null</font>
b[1]=<font color=#0000ff>null</font>
b[2]=<font color=#0000ff>null</font>
b[3]=<font color=#0000ff>null</font>
b[4]=<font color=#0000ff>null</font>
c.length = 4
d.length = 3
a.length = 3
a.length = 2
f.length = 5
f[0]=0
f[1]=0
f[2]=0
f[3]=0
f[4]=0
g.length = 4
h.length = 3
e.length = 3
e.length = 2</PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The array <B>a</B> is initially
just a <A NAME="Index733"></A><B>null</B> handle, and the compiler prevents you
from doing anything with this handle until you’ve properly initialized it.
The array <B>b</B> is initialized to point to an array of <B>Weeble</B> handles,
but no actual <B>Weeble</B> objects are ever placed in that array. However, you
can still ask what the size of the array is, since <B>b</B> is pointing to a
legitimate object. This brings up a slight drawback: you can’t find out
how many elements are actually <I>in</I> the array, since <B>length</B> tells
you only how many elements <I>can</I> be placed in the array; that is, the size
of the array object, not the number of elements it actually holds. However, when
an array object is created its handles are automatically initialized to
<B>null</B> so you can see whether a particular array slot has an object in it
by checking to see whether it’s <B>null</B>. Similarly, an array of
primitives is automatically initialized to zero for numeric types, <B>null
</B>for <B>char</B>, and<B> false</B> for <B>boolean</B>.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Array <B>c</B> shows the creation
of the array object followed by the assignment of <B>Weeble</B> objects to all
the slots in the array. Array <B>d</B> shows the “aggregate
initialization” syntax that causes the array object to be created
(implicitly with <B>new</B> on the heap, just like for array <B>c</B>)
<I>and</I> initialized with <B>Weeble</B> objects, all in one
statement.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The expression</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE>a = d;</PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">shows how you can take a handle
that’s attached to one array object and assign it to another array object,
just as you can do with any other type of object handle. Now both <B>a</B> and
<B>d</B> are pointing to the same array object on the heap.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><A NAME="Index734"></A><FONT FACE="Georgia">Java 1.1
adds a new array initialization syntax, which could be thought of as a
“dynamic aggregate initialization.” The Java
1.0<A NAME="Index735"></A> aggregate initialization used by <B>d</B> must be
used at the point of <B>d</B>’s definition, but with the Java 1.1 syntax
you can create and initialize an array object anywhere. For example, suppose
<B>hide( )</B> is a method that takes an array of <B>Weeble</B> objects.
You could call it by saying:</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE>hide(d);</PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">but in Java 1.1 you can also
dynamically create the array you want to pass as the argument:</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE>hide(<font color=#0000ff>new</font> Weeble[] { <font color=#0000ff>new</font> Weeble(), <font color=#0000ff>new</font> Weeble() });</PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">This new syntax provides a more
convenient way to write code in some situations.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The second part of the above
example shows that primitive arrays work just like object arrays <I>except</I>
that primitive arrays hold the primitive values
directly.</FONT><A NAME="_Toc375545349"></A><BR></P></DIV>
<A NAME="Heading242"></A><FONT FACE = "Verdana"><H4 ALIGN="LEFT">
Collections of primitives<BR><A NAME="Index736"></A><A NAME="Index737"></A></H4></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Collection classes can hold only
handles to objects. An array, however, can be created to hold primitives
directly, as well as handles to objects. It <I>is</I> possible to use the
“wrapper” classes such as <B>Integer</B>, <B>Double,</B> etc. to
place primitive values inside a collection, but as you’ll see later in
this chapter in the <B>WordCount.java</B> example, the wrapper classes for
primitives are only somewhat useful anyway. Whether you put primitives in arrays
or wrap them in a class that’s placed in a collection is a question of
efficiency. It’s much more efficient to create and access an array of
primitives than a collection of wrapped primitives.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Of course, if you’re using a
primitive type and you need the flexibility of a collection that automatically
expands when more space is needed, the array won’t work and you’re
forced to use a collection of wrapped primitives. You might think that there
should be a specialized type of <B>Vector</B> for each of the primitive data
types, but Java doesn’t provide this for you. Some sort of templatizing
mechanism might someday provide a better way for Java to handle this
problem.</FONT><A NAME="fnB32" HREF="#fn32">[32]</A><A NAME="_Toc408018565"></A><BR></P></DIV>
<A NAME="Heading243"></A><FONT FACE = "Verdana"><H3 ALIGN="LEFT">
Returning an array</H3></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Suppose you’re writing a
method and you don’t just want to return one thing, but a whole bunch of
things. Languages like C and C++ make this difficult because you can’t
just return an array, only a pointer to an array. This introduces problems
because it becomes messy to control the lifetime of the array, which easily
leads to memory leaks.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Java takes a similar approach, but
you just “return an array.” Actually, of course, you’re
returning a handle to an array, but with Java you never worry about
responsibility for that array – it will be around as long as you need it,
and the garbage collector will clean it up when you’re
done.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">As an example, consider returning
an array of <B>String</B>:</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: IceCream.java</font>
<font color=#009900>// Returning arrays from methods</font>
<font color=#0000ff>public</font> <font color=#0000ff>class</font> IceCream {
<font color=#0000ff>static</font> String[] flav = {
<font color=#004488>"Chocolate"</font>, <font color=#004488>"Strawberry"</font>,
<font color=#004488>"Vanilla Fudge Swirl"</font>, <font color=#004488>"Mint Chip"</font>,
<font color=#004488>"Mocha Almond Fudge"</font>, <font color=#004488>"Rum Raisin"</font>,
<font color=#004488>"Praline Cream"</font>, <font color=#004488>"Mud Pie"</font>
};
<font color=#0000ff>static</font> String[] flavorSet(<font color=#0000ff>int</font> n) {
<font color=#009900>// Force it to be positive & within bounds:</font>
n = Math.abs(n) % (flav.length + 1);
String[] results = <font color=#0000ff>new</font> String[n];
<font color=#0000ff>int</font>[] picks = <font color=#0000ff>new</font> <font color=#0000ff>int</font>[n];
<font color=#0000ff>for</font>(<font color=#0000ff>int</font> i = 0; i < picks.length; i++)
picks[i] = -1;
<font color=#0000ff>for</font>(<font color=#0000ff>int</font> i = 0; i < picks.length; i++) {
retry:
<font color=#0000ff>while</font>(<font color=#0000ff>true</font>) {
<font color=#0000ff>int</font> t =
(<font color=#0000ff>int</font>)(Math.random() * flav.length);
<font color=#0000ff>for</font>(<font color=#0000ff>int</font> j = 0; j < i; j++)
<font color=#0000ff>if</font>(picks[j] == t) <font color=#0000ff>continue</font> retry;
picks[i] = t;
results[i] = flav[t];
<font color=#0000ff>break</font>;
}
}
<font color=#0000ff>return</font> results;
}
<font color=#0000ff>public</font> <font color=#0000ff>static</font> <font color=#0000ff>void</font> main(String[] args) {
<font color=#0000ff>for</font>(<font color=#0000ff>int</font> i = 0; i < 20; i++) {
System.out.println(
<font color=#004488>"flavorSet("</font> + i + <font color=#004488>") = "</font>);
String[] fl = flavorSet(flav.length);
<font color=#0000ff>for</font>(<font color=#0000ff>int</font> j = 0; j < fl.length; j++)
System.out.println(<font color=#004488>"\t"</font> + fl[j]);
}
}
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The method <B>flavorSet( )</B>
creates an array of <B>String</B> called <B>results</B>. The size of this array
is <B>n</B>, determined by the argument you pass into the method. Then it
proceeds to choose flavors randomly from the array <B>flav</B> and place them
into <B>results</B>, which it finally returns. Returning an array is just like
returning any other object – it’s a handle. It’s not important
that the array was created within <B>flavorSet( )</B>, or that the array
was created anyplace else, for that matter. The garbage collector takes care of
cleaning up the array when you’re done with it, and the array will persist
for as long as you need it.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">As an aside, notice that when
<B>flavorSet( )</B> chooses flavors randomly, it ensures that a random
choice hasn’t been picked before. This is performed in a seemingly
infinite <B>while</B> loop that keeps making random choices until it finds one
that’s not already in the <B>picks</B> array. (Of course, a <B>String</B>
comparison could also have been performed to see if the random choice was
already in the <B>results</B> array, but <B>String</B> comparisons are
inefficient.) If it’s successful it adds the entry and <B>break</B>s out
to go find the next one (<B>i </B>gets incremented). But if <B>t</B> is a number
that’s already in <B>picks</B>, then a labeled <B>continue</B> is used to
jump back two levels, which forces a new <B>t</B> to be selected. It’s
particularly convincing to watch this happen with a debugger.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia"><B>main( )</B> prints out 20
full sets of flavors, so you can see that <B>flavorSet( )</B> chooses the
flavors in a random order each time. It’s easiest to see this if you
redirect the output into a file. And while you’re looking at the file,
remember, you’re not really hungry. (You just <I>want</I> the ice cream,
you don’t <I>need</I>
it.)</FONT><A NAME="_Toc375545350"></A><A NAME="_Toc408018566"></A><BR></P></DIV>
<A NAME="Heading244"></A><FONT FACE = "Verdana"><H2 ALIGN="LEFT">
Collections</H2></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">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><I>collection classes</I> to solve this problem:
<A NAME="Index739"></A><B>Vector</B>, <A NAME="Index740"></A><B>BitSet</B>,<B>
<A NAME="Index741"></A>Stack</B>, and <A NAME="Index742"></A><B>Hashtable</B>.
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><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Among their other characteristics
– <B>Stack</B>, for example, implements a LIFO (last-in, first-out)
sequence, and <B>Hashtable</B> is an <A NAME="Index743"></A><I>associative
array</I> 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><BR></P></DIV>
<A NAME="Heading245"></A><FONT FACE = "Verdana"><H3 ALIGN="LEFT">
Disadvantage: unknown type</H3></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -