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

📄 chapter08.html

📁 java 是一个很好的网络开发环境。由于它是通过解释的方法
💻 HTML
📖 第 1 页 / 共 5 页
字号:
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 <B>Object</B>, which is of course every object in
Java, since it&#8217;s the root of all the classes. (Of course, this
doesn&#8217;t include primitive types, since they aren&#8217;t inherited from
anything.) This is a great solution, except for these reasons:</FONT><BR></P></DIV>
<OL>
<LI><FONT FACE="Georgia">	Since the type information is thrown away when
you put an object handle into a collection, <I>any</I> 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="Georgia">	Since the type information is
lost, the only thing the collection knows it holds is a handle to an
<B>Object</B>. You must perform a <A NAME="Index744"></A>cast to the correct
type before you use
it.</FONT></OL><DIV ALIGN="LEFT"><P><FONT FACE="Georgia">On the up side, Java
won&#8217;t let you <I>misuse</I> 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&#8217;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&#8217;ll get an exception at
run-time.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Here&#8217;s an
example:</FONT><BR></P></DIV>

<BLOCKQUOTE><FONT SIZE = "+1"><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(<font color=#004488>"Cat #"</font> + 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(<font color=#004488>"Dog #"</font> + 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 &lt; 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 &lt; cats.size(); i++)
      ((Cat)cats.elementAt(i)).print();
    <font color=#009900>// Dog is detected only at run-time</font>
  }
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">You can see that using a
<B>Vector</B> is straightforward: create one, put objects in using
<A NAME="Index745"></A><A NAME="Index746"></A><B>addElement(&#160;),</B> and
later get them out with
<A NAME="Index747"></A><A NAME="Index748"></A><B>elementAt(&#160;).</B> (Note
that <B>Vector</B> has a method
<A NAME="Index749"></A><A NAME="Index750"></A><B>size(&#160;)</B> to let you
know how many elements have been added so you don&#8217;t inadvertently run off
the end and cause an exception.)</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The classes <B>Cat</B> and
<B>Dog</B> are distinct &#8211; they have nothing in common except that they are
<B>Object</B>s. (If you don&#8217;t explicitly say what class you&#8217;re
inheriting from, you automatically inherit from <B>Object.</B>) The
<B>Vector</B> class, which comes from <B>java.util</B>, holds <B>Object</B>s, so
not only can you put <B>Cat</B> objects into this collection using the <B>Vector
</B>method <B>addElement(&#160;)</B>, but you can also add <B>Dog</B> objects
without complaint at either compile-time or run-time. When you go to fetch out
what you think are <B>Cat</B> objects using the <B>Vector</B> method
<B>elementAt(&#160;)</B>, you get back a handle to an <B>Object</B> that you
must cast to a <B>Cat</B>. Then you need to surround the entire expression with
parentheses to force the evaluation of the cast before calling the
<B>print(&#160;)</B> method for <B>Cat</B>, otherwise you&#8217;ll get a syntax
error. Then, at run-time, when you try to cast the <B>Dog</B> object to a
<B>Cat</B>, you&#8217;ll get an exception.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">This is more than just an
annoyance. It&#8217;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&#8217;s convenient to start with some
standardized collection classes for programming, despite the scarcity and
awkwardness.</FONT><BR></P></DIV>
<A NAME="Heading246"></A><FONT FACE = "Verdana"><H4 ALIGN="LEFT">
Sometimes it works right anyway</H4></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">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 <B>String</B> class has some extra help from
the compiler to make it work smoothly. Whenever the compiler expects a
<B>String</B> object and it hasn&#8217;t got one, it will automatically call the
<A NAME="Index751"></A><A NAME="Index752"></A><B>toString(&#160;)</B> method
that&#8217;s defined in <B>Object</B> and can be overridden by any Java class.
This method produces the desired <B>String</B> object, which is then used
wherever it was wanted.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Thus, all you need to do to make
objects of your class print out is to override the <B>toString(&#160;)</B>
method, as shown in the following example:</FONT><BR></P></DIV>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: WorksAnyway.java</font>
<font color=#009900>// In special cases, things just seem</font>
<font color=#009900>// to work correctly.</font>
<font color=#0000ff>import</font> java.util.*;

<font color=#0000ff>class</font> Mouse {
  <font color=#0000ff>private</font> <font color=#0000ff>int</font> mouseNumber;
  Mouse(<font color=#0000ff>int</font> i) {
    mouseNumber = i;
  }
  <font color=#009900>// Magic method:</font>
  <font color=#0000ff>public</font> String toString() {
    <font color=#0000ff>return</font> <font color=#004488>"This is Mouse #"</font> + mouseNumber;
  }
  <font color=#0000ff>void</font> print(String msg) {
    <font color=#0000ff>if</font>(msg != <font color=#0000ff>null</font>) System.out.println(msg);
    System.out.println(
      <font color=#004488>"Mouse number "</font> + mouseNumber);
  }
}

<font color=#0000ff>class</font> MouseTrap {
  <font color=#0000ff>static</font> <font color=#0000ff>void</font> caughtYa(Object m) {
    Mouse mouse = (Mouse)m; <font color=#009900>// Cast from Object</font>
    mouse.print(<font color=#004488>"Caught one!"</font>);
  }
}

<font color=#0000ff>public</font> <font color=#0000ff>class</font> WorksAnyway {
  <font color=#0000ff>public</font> <font color=#0000ff>static</font> <font color=#0000ff>void</font> main(String[] args) {
    Vector mice = <font color=#0000ff>new</font> Vector();
    <font color=#0000ff>for</font>(<font color=#0000ff>int</font> i = 0; i &lt; 3; i++)
      mice.addElement(<font color=#0000ff>new</font> Mouse(i));
    <font color=#0000ff>for</font>(<font color=#0000ff>int</font> i = 0; i &lt; mice.size(); i++) {
      <font color=#009900>// No cast necessary, automatic call</font>
      <font color=#009900>// to Object.toString():</font>
      System.out.println(
        <font color=#004488>"Free mouse: "</font> + mice.elementAt(i));
      MouseTrap.caughtYa(mice.elementAt(i));
    }
  }
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">You can see the redefinition of
<B>toString(&#160;)</B> in <B>Mouse</B>. In the second <B>for</B> loop in
<B>main(&#160;)</B> you find the statement:</FONT><BR></P></DIV>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE>System.out.println(<font color=#004488>"Free mouse: "</font> + mice.elementAt(i));</PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">After the &#8216;<B>+</B>&#8217;
sign the compiler expects to see a
<A NAME="Index753"></A><A NAME="Index754"></A><B>String</B> object.
<B>elementAt(&#160;)</B> produces an <B>Object</B>, so to get the desired
<B>String</B> the compiler implicitly calls <B>toString(&#160;)</B>.
Unfortunately, you can work this kind of magic only with <B>String</B>; it
isn&#8217;t available for any other type.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">A second approach to hiding the
cast has been placed inside <B>Mousetrap</B>. The <B>caughtYa(&#160;)</B> method
accepts not a <B>Mouse</B>, but an <B>Object,</B> which it then casts to a
<B>Mouse</B>. This is quite presumptuous, of course, since by accepting an
<B>Object</B> anything could be passed to the method. However, if the cast is
incorrect &#8211; if you passed the wrong type &#8211; you&#8217;ll get an
exception at run-time. This is not as good as compile-time checking but
it&#8217;s still robust. Note that in the use of this method:</FONT><BR></P></DIV>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE>MouseTrap.caughtYa(mice.elementAt(i));</PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">no cast is
necessary.</FONT><BR></P></DIV>
<A NAME="Heading247"></A><FONT FACE = "Verdana"><H4 ALIGN="LEFT">
Making a type-conscious
Vector<BR><A NAME="Index755"></A><A NAME="Index756"></A></H4></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">You might not want to give up on
this issue just yet. A more ironclad solution is to create a new class using the
<B>Vector</B>, such that it will accept only your type and produce only your
type:</FONT><BR></P></DIV>

<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: GopherVector.java</font>
<font color=#009900>// A type-conscious Vector</font>
<font color=#0000ff>import</font> java.util.*;

<font color=#0000ff>class</font> Gopher {
  <font color=#0000ff>private</font> <font color=#0000ff>int</font> gopherNumber;
  Gopher(<font color=#0000ff>int</font> i) {
    gopherNumber = i;
  }
  <font color=#0000ff>void</font> print(String msg) {
    <font color=#0000ff>if</font>(msg != <font color=#0000ff>null</font>) System.out.println(msg);
    System.out.println(
      <font color=#004488>"Gopher number "</font> + gopherNumber);
  }
}

<font color=#0000ff>class</font> GopherTrap {
  <font color=#0000ff>static</font> <font color=#0000ff>void</font> caughtYa(Gopher g) {
    g.print(<font color=#004488>"Caught one!"</font>);
  }
}

<font color=#0000ff>class</font> GopherVector {
  <font color=#0000ff>private</font> Vector v = <font color=#0000ff>new</font> Vector();
  <font color=#0000ff>public</font> <font color=#0000ff>void</font> addElement(Gopher m) {
    v.addElement(m);
  }
  <font color=#0000ff>public</font> Gopher elementAt(<font color=#0000ff>int</font> index) {
    <font color=#0000ff>return</font> (Gopher)v.elementAt(index);
  }
  <font color=#0000ff>public</font> <font color=#0000ff>int</font> size() { <font color=#0000ff>return</font> v.size(); }

⌨️ 快捷键说明

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