📄 chapter16.html
字号:
<A NAME="Index2952"></A><A NAME="Index2953"></A>inner classes (which are made
<B>static</B>, so they are inner classes only for code organization purposes)
describing exceptions that can occur. This is followed by a <B>Vector
trashTypes</B>, which is used to hold the <B>Class</B> handles.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">In <B>Trash.factory( )</B>,
the <B>String</B> inside the <B>Info </B>object <B>id </B>(a different version
of the <B>Info</B> class than that of the prior discussion) contains the type
name of the <B>Trash </B>to be created; this <B>String</B> is compared to the
<B>Class</B> names in the list. If there’s a match, then that’s the
object to create. Of course, there are many ways to determine what object you
want to make. This one is used so that information read in from a file can be
turned into objects.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Once you’ve discovered which
kind of <B>Trash</B> to create, then the <A NAME="Index2954"></A>reflection
methods come into play. The
<A NAME="Index2955"></A><B>getConstructor( )</B> method takes an argument
that’s an array of <A NAME="Index2956"></A><B>Class</B> handles. This
array represents the arguments, in their proper order, for the constructor that
you’re looking for. Here, the
<A NAME="Index2957"></A><A NAME="Index2958"></A>array is dynamically created
using the Java 1.1<A NAME="Index2959"></A> array-creation
syntax:</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#0000ff>new</font> Class[] {<font color=#0000ff>double</font>.<font color=#0000ff>class</font>}</PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">This code assumes that every
<B>Trash</B> type has a constructor that takes a <B>double </B>(and notice that
<B>double.class</B> is distinct from <B>Double.class</B>). It’s also
possible, for a more flexible solution, to call
<A NAME="Index2960"></A><B>getConstructors( )</B>, which returns an array
of the possible constructors.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">What comes back from
<B>getConstructor( ) </B>is a handle to a
<A NAME="Index2961"></A><B>Constructor</B> object (part of
<B>java.lang.reflect</B>). You call the constructor dynamically with the method
<A NAME="Index2962"></A><B>newInstance( )</B>, which takes an array of
<B>Object</B> containing the actual arguments. This array is again created using
the Java 1.1<A NAME="Index2963"></A> syntax:</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#0000ff>new</font> Object[]{<font color=#0000ff>new</font> Double(info.data)}</PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">In this case, however, the
<B>double</B> must be placed inside a wrapper class so that it can be part of
this array of objects. The process of calling <B>newInstance( )</B>
extracts the <B>double</B>, but you can see it is a bit confusing – an
argument might be a <B>double </B>or a <B>Double</B>, but when you make the call
you must always pass in a <B>Double</B>. Fortunately, this issue exists only for
the primitive types.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Once you understand how to do it,
the process of creating a new object given only a <B>Class</B> handle is
remarkably simple. Reflection also allows you to call methods in this same
dynamic fashion.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Of course, the appropriate
<B>Class</B> handle might not be in the <B>trashTypes</B> list. In this case,
the <B>return</B> in the inner loop is never executed and you’ll drop out
at the end. Here, the program tries to rectify the situation by loading the
<B>Class</B> object dynamically and adding it to the <B>trashTypes</B> list. If
it still can’t be found something is really wrong, but if the load is
successful then the <B>factory</B> method is called
<A NAME="Index2964"></A><A NAME="Index2965"></A>recursively to try
again.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">As you’ll see, the beauty of
this design is that this code doesn’t need to be changed, regardless of
the different situations it will be used in (assuming that all <B>Trash</B>
subclasses contain a constructor that takes a single <B>double</B>
argument).</FONT><BR></P></DIV>
<A NAME="Heading559"></A><FONT FACE = "Verdana"><H4 ALIGN="LEFT">
Trash subclasses</H4></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">To fit into the prototyping scheme,
the only thing that’s required of each new subclass of <B>Trash</B> is
that it contain a constructor that takes a <B>double</B> argument. Java
1.1<A NAME="Index2966"></A> reflection handles everything else.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Here are the different types of
<B>Trash</B>, each in their own file but part of the <B>Trash</B> package
(again, to facilitate reuse within the chapter):</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: Aluminum.java </font>
<font color=#009900>// The Aluminum class with prototyping</font>
<font color=#0000ff>package</font> c16.trash;
<font color=#0000ff>public</font> <font color=#0000ff>class</font> Aluminum <font color=#0000ff>extends</font> Trash {
<font color=#0000ff>private</font> <font color=#0000ff>static</font> <font color=#0000ff>double</font> val = 1.67f;
<font color=#0000ff>public</font> Aluminum(<font color=#0000ff>double</font> wt) { <font color=#0000ff>super</font>(wt); }
<font color=#0000ff>public</font> <font color=#0000ff>double</font> value() { <font color=#0000ff>return</font> val; }
<font color=#0000ff>public</font> <font color=#0000ff>static</font> <font color=#0000ff>void</font> value(<font color=#0000ff>double</font> newVal) {
val = newVal;
}
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: Paper.java </font>
<font color=#009900>// The Paper class with prototyping</font>
<font color=#0000ff>package</font> c16.trash;
<font color=#0000ff>public</font> <font color=#0000ff>class</font> Paper <font color=#0000ff>extends</font> Trash {
<font color=#0000ff>private</font> <font color=#0000ff>static</font> <font color=#0000ff>double</font> val = 0.10f;
<font color=#0000ff>public</font> Paper(<font color=#0000ff>double</font> wt) { <font color=#0000ff>super</font>(wt); }
<font color=#0000ff>public</font> <font color=#0000ff>double</font> value() { <font color=#0000ff>return</font> val; }
<font color=#0000ff>public</font> <font color=#0000ff>static</font> <font color=#0000ff>void</font> value(<font color=#0000ff>double</font> newVal) {
val = newVal;
}
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: Glass.java </font>
<font color=#009900>// The Glass class with prototyping</font>
<font color=#0000ff>package</font> c16.trash;
<font color=#0000ff>public</font> <font color=#0000ff>class</font> Glass <font color=#0000ff>extends</font> Trash {
<font color=#0000ff>private</font> <font color=#0000ff>static</font> <font color=#0000ff>double</font> val = 0.23f;
<font color=#0000ff>public</font> Glass(<font color=#0000ff>double</font> wt) { <font color=#0000ff>super</font>(wt); }
<font color=#0000ff>public</font> <font color=#0000ff>double</font> value() { <font color=#0000ff>return</font> val; }
<font color=#0000ff>public</font> <font color=#0000ff>static</font> <font color=#0000ff>void</font> value(<font color=#0000ff>double</font> newVal) {
val = newVal;
}
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">And here’s a new type of
<B>Trash</B>:</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: Cardboard.java </font>
<font color=#009900>// The Cardboard class with prototyping</font>
<font color=#0000ff>package</font> c16.trash;
<font color=#0000ff>public</font> <font color=#0000ff>class</font> Cardboard <font color=#0000ff>extends</font> Trash {
<font color=#0000ff>private</font> <font color=#0000ff>static</font> <font color=#0000ff>double</font> val = 0.23f;
<font color=#0000ff>public</font> Cardboard(<font color=#0000ff>double</font> wt) { <font color=#0000ff>super</font>(wt); }
<font color=#0000ff>public</font> <font color=#0000ff>double</font> value() { <font color=#0000ff>return</font> val; }
<font color=#0000ff>public</font> <font color=#0000ff>static</font> <font color=#0000ff>void</font> value(<font color=#0000ff>double</font> newVal) {
val = newVal;
}
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">You can see that, other than the
constructor, there’s nothing special about any of these
classes.</FONT><BR></P></DIV>
<A NAME="Heading560"></A><FONT FACE = "Verdana"><H4 ALIGN="LEFT">
Parsing Trash from an external file</H4></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The information about <B>Trash</B>
objects will be read from an outside file. The file has all of the necessary
information about each piece of trash on a single line in the form
<B>Trash:weight</B>, such as:</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE>c16.Trash.Glass:54
c16.Trash.Paper:22
c16.Trash.Paper:11
c16.Trash.Glass:17
c16.Trash.Aluminum:89
c16.Trash.Paper:88
c16.Trash.Aluminum:76
c16.Trash.Cardboard:96
c16.Trash.Aluminum:25
c16.Trash.Aluminum:34
c16.Trash.Glass:11
c16.Trash.Glass:68
c16.Trash.Glass:43
c16.Trash.Aluminum:27
c16.Trash.Cardboard:44
c16.Trash.Aluminum:18
c16.Trash.Paper:91
c16.Trash.Glass:63
c16.Trash.Glass:50
c16.Trash.Glass:80
c16.Trash.Aluminum:81
c16.Trash.Cardboard:12
c16.Trash.Glass:12
c16.Trash.Glass:54
c16.Trash.Aluminum:36
c16.Trash.Aluminum:93
c16.Trash.Glass:93
c16.Trash.Paper:80
c16.Trash.Glass:36
c16.Trash.Glass:12
c16.Trash.Glass:60
c16.Trash.Paper:66
c16.Trash.Aluminum:36
c16.Trash.Cardboard:22</PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Note that the class path must be
included when giving the class names, otherwise the class will not be
found.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">To parse this, the line is read and
the <A NAME="Index2967"></A><B>String </B>method
<A NAME="Index2968"></A><B>indexOf( )</B> produces the index of the
‘<B>:</B>’. This is first used with the <B>String </B>method
<A NAME="Index2969"></A><A NAME="Index2970"></A><B>substring( ) </B>to
extract the name of the trash type, and next to get the weight that is turned
into a <B>double </B>with the <B>static
<A NAME="Index2971"></A>Double.valueOf( ) </B>method. The
<A NAME="Index2972"></A><A NAME="Index2973"></A><B>trim( )</B> method
removes white space at both ends of a string.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The <B>Trash </B>parser is placed
in a separate file since it will be reused throughout this
chapter:</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: ParseTrash.java </font>
<font color=#009900>// Open a file and parse its contents into</font>
<font color=#009900>// Trash objects, placing each into a Vector</font>
<font color=#0000ff>package</font> c16.trash;
<font color=#0000ff>import</font> java.util.*;
<font color=#0000ff>import</font> java.io.*;
<font color=#0000ff>public</font> <font color=#0000ff>class</font> ParseTrash {
<font color=#0000ff>public</font> <font color=#0000ff>static</font> <font color=#0000ff>void</font>
fillBin(String filename, Fillable bin) {
<font color=#0000ff>try</font> {
BufferedReader data =
<font color=#0000ff>new</font> BufferedReader(
<font color=#0000ff>new</font> FileReader(filename));
String buf;
<font color=#0000ff>while</font>((buf = data.readLine())!= <font color=#0000ff>null</font>) {
String type = buf.substring(0,
buf.indexOf(':')).trim();
<font color=#0000ff>double</font> weight = Double.valueOf(
buf.substring(buf.indexOf(':') + 1)
.trim()).doubleValue();
bin.addTrash(
Trash.factory(
<font color=#0000ff>new</f
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -