📄 chapter11.html
字号:
must be loaded. Thus, the <B>.class</B> file for that particular type must still
be available to the JVM, either on the local machine or across the network. So
the true <A NAME="Index1425"></A><A NAME="Index1426"></A>difference between RTTI
and reflection is that with RTTI, the compiler opens and examines the
<B>.class</B> file at compile time. Put another way, you can call all the
methods of an object in the “normal” way. With reflection, the
<B>.class</B> file is unavailable at compile time; it is opened and examined by
the run-time environment.</FONT><A NAME="_Toc408018650"></A><BR></P></DIV>
<A NAME="Heading360"></A><FONT FACE = "Verdana"><H3 ALIGN="LEFT">
A class method extractor</H3></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">You’ll rarely need to use the
reflection tools directly; they’re in the language to support the other
Java features such as object serialization (described in Chapter 10), Java
Beans, and RMI (described later in the book). However, there are times when
it’s quite useful to be able to dynamically extract information about a
class. One extremely useful tool is a class method extractor. As mentioned
before, looking at a class definition source code or online documentation shows
only the methods that are defined or overridden <I>within that class
definition</I>. But there could be dozens more available to you that have come
from base classes. To locate these is both tedious and time consuming.
Fortunately, reflection provides a way to write a simple tool that will
automatically show you the entire interface. Here’s the way it
works:</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: ShowMethods.java</font>
<font color=#009900>// Using Java 1.1 reflection to show all the </font>
<font color=#009900>// methods of a class, even if the methods are </font>
<font color=#009900>// defined in the base class.</font>
<font color=#0000ff>import</font> java.lang.reflect.*;
<font color=#0000ff>public</font> <font color=#0000ff>class</font> ShowMethods {
<font color=#0000ff>static</font> <font color=#0000ff>final</font> String usage =
<font color=#004488>"usage: \n"</font> +
<font color=#004488>"ShowMethods qualified.class.name\n"</font> +
<font color=#004488>"To show all methods in class or: \n"</font> +
<font color=#004488>"ShowMethods qualified.class.name word\n"</font> +
<font color=#004488>"To search for methods involving 'word'"</font>;
<font color=#0000ff>public</font> <font color=#0000ff>static</font> <font color=#0000ff>void</font> main(String[] args) {
<font color=#0000ff>if</font>(args.length < 1) {
System.out.println(usage);
System.exit(0);
}
<font color=#0000ff>try</font> {
Class c = Class.forName(args[0]);
Method[] m = c.getMethods();
Constructor[] ctor = c.getConstructors();
<font color=#0000ff>if</font>(args.length == 1) {
<font color=#0000ff>for</font> (<font color=#0000ff>int</font> i = 0; i < m.length; i++)
System.out.println(m[i].toString());
<font color=#0000ff>for</font> (<font color=#0000ff>int</font> i = 0; i < ctor.length; i++)
System.out.println(ctor[i].toString());
}
<font color=#0000ff>else</font> {
<font color=#0000ff>for</font> (<font color=#0000ff>int</font> i = 0; i < m.length; i++)
<font color=#0000ff>if</font>(m[i].toString()
.indexOf(args[1])!= -1)
System.out.println(m[i].toString());
<font color=#0000ff>for</font> (<font color=#0000ff>int</font> i = 0; i < ctor.length; i++)
<font color=#0000ff>if</font>(ctor[i].toString()
.indexOf(args[1])!= -1)
System.out.println(ctor[i].toString());
}
} <font color=#0000ff>catch</font> (ClassNotFoundException e) {
System.out.println(<font color=#004488>"No such class: "</font> + e);
}
}
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The <B>Class</B> methods
<A NAME="Index1427"></A><A NAME="Index1428"></A><B>getMethods( )</B> and
<A NAME="Index1429"></A><A NAME="Index1430"></A><B>getConstructors( )</B>
return an array of <B>Method</B> and <B>Constructor</B>, respectively. Each of
these classes has further methods to dissect the names, arguments, and return
values of the methods they represent. But you can also just use
<B>toString( )</B>, as is done here, to produce a <B>String</B> with the
entire method signature. The rest of the code is just for extracting command
line information, determining if a particular signature matches with your target
string (using
<A NAME="Index1431"></A><A NAME="Index1432"></A><B>indexOf( )</B>), and
printing the results.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">This shows reflection in action,
since the result produced by <B>Class.forName( )</B> cannot be known at
compile-time, and therefore all the method signature information is being
extracted at run-time. If you investigate your online documentation on
reflection, you’ll see that there is enough support to actually set up and
make a method call on an object that’s totally unknown at compile-time.
Again, this is something you’ll probably never need to do yourself –
the support is there for Java and so a programming environment can manipulate
Java Beans – but it’s interesting.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">An interesting experiment is to run
<B>java ShowMethods ShowMethods</B>. This produces a listing that includes a
<B>public</B> default constructor, even though you can see from the code that no
constructor was defined. The constructor you see is the one that’s
automatically synthesized by the compiler. If you then make <B>ShowMethods</B> a
non-<B>public</B> class (that is, friendly), the synthesized default constructor
no longer shows up in the output. The synthesized default constructor is
automatically given the same access as the class.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The output for <B>ShowMethods</B>
is still a little tedious. For example, here’s a portion of the output
produced by invoking <B>java ShowMethods java.lang.String</B>:</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#0000ff>public</font> <font color=#0000ff>boolean</font>
java.lang.String.startsWith(java.lang.String,<font color=#0000ff>int</font>)
<font color=#0000ff>public</font> <font color=#0000ff>boolean</font>
java.lang.String.startsWith(java.lang.String)
<font color=#0000ff>public</font> <font color=#0000ff>boolean</font>
java.lang.String.endsWith(java.lang.String)</PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">It would be even nicer if the
qualifiers like <B>java.lang</B> could be stripped off. The
<A NAME="Index1433"></A><A NAME="Index1434"></A><B>StreamTokenizer</B> class
introduced in the previous chapter can help solve this problem:</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: ShowMethodsClean.java</font>
<font color=#009900>// ShowMethods with the qualifiers stripped</font>
<font color=#009900>// to make the results easier to read</font>
<font color=#0000ff>import</font> java.lang.reflect.*;
<font color=#0000ff>import</font> java.io.*;
<font color=#0000ff>public</font> <font color=#0000ff>class</font> ShowMethodsClean {
<font color=#0000ff>static</font> <font color=#0000ff>final</font> String usage =
<font color=#004488>"usage: \n"</font> +
<font color=#004488>"ShowMethodsClean qualified.class.name\n"</font> +
<font color=#004488>"To show all methods in class or: \n"</font> +
<font color=#004488>"ShowMethodsClean qualif.class.name word\n"</font> +
<font color=#004488>"To search for methods involving 'word'"</font>;
<font color=#0000ff>public</font> <font color=#0000ff>static</font> <font color=#0000ff>void</font> main(String[] args) {
<font color=#0000ff>if</font>(args.length < 1) {
System.out.println(usage);
System.exit(0);
}
<font color=#0000ff>try</font> {
Class c = Class.forName(args[0]);
Method[] m = c.getMethods();
Constructor[] ctor = c.getConstructors();
<font color=#009900>// Convert to an array of cleaned Strings:</font>
String[] n =
<font color=#0000ff>new</font> String[m.length + ctor.length];
<font color=#0000ff>for</font>(<font color=#0000ff>int</font> i = 0; i < m.length; i++) {
String s = m[i].toString();
n[i] = StripQualifiers.strip(s);
}
<font color=#0000ff>for</font>(<font color=#0000ff>int</font> i = 0; i < ctor.length; i++) {
String s = ctor[i].toString();
n[i + m.length] =
StripQualifiers.strip(s);
}
<font color=#0000ff>if</font>(args.length == 1)
<font color=#0000ff>for</font> (<font color=#0000ff>int</font> i = 0; i < n.length; i++)
System.out.println(n[i]);
<font color=#0000ff>else</font>
<font color=#0000ff>for</font> (<font color=#0000ff>int</font> i = 0; i < n.length; i++)
<font color=#0000ff>if</font>(n[i].indexOf(args[1])!= -1)
System.out.println(n[i]);
} <font color=#0000ff>catch</font> (ClassNotFoundException e) {
System.out.println(<font color=#004488>"No such class: "</font> + e);
}
}
}
<font color=#0000ff>class</font> StripQualifiers {
<font color=#0000ff>private</font> StreamTokenizer st;
<font color=#0000ff>public</font> StripQualifiers(String qualified) {
st = <font color=#0000ff>new</font> StreamTokenizer(
<font color=#0000ff>new</font> StringReader(qualified));
st.ordinaryChar(' '); <font color=#009900>// Keep the spaces</font>
}
<font color=#0000ff>public</font> String getNext() {
String s = <font color=#0000ff>null</font>;
<font color=#0000ff>try</font> {
<font color=#0000ff>if</font>(st.nextToken() !=
StreamTokenizer.TT_EOF) {
<font color=#0000ff>switch</font>(st.ttype) {
<font color=#0000ff>case</font> StreamTokenizer.TT_EOL:
s = <font color=#0000ff>null</font>;
<font color=#0000ff>break</font>;
<font color=#0000ff>case</font> StreamTokenizer.TT_NUMBER:
s = Double.toString(st.nval);
<font color=#0000ff>break</font>;
<font color=#0000ff>case</font> StreamTokenizer.TT_WORD:
s = <font color=#0000ff>new</font> String(st.sval);
<font color=#0000ff>break</font>;
<font color=#0000ff>default</font>: <font color=#009900>// single character in ttype</font>
s = String.valueOf((<font color=#0000ff>char</font>)st.ttype);
}
}
} <font color=#0000ff>catch</font>(IOException e) {
System.out.println(e);
}
<font color=#0000ff>return</font> s;
}
<font color=#0000ff>public</font> <font color=#0000ff>static</font> String strip(String qualified) {
StripQualifiers sq =
<font color=#0000ff>new</font> StripQualifiers(qualified);
String s = <font color=#004488>""</font>, si;
<font color=#0000ff>while</font>((si = sq.getNext()) != <font color=#0000ff>null</font>) {
<font color=#0000ff>int</font> lastDot = si.lastIndexOf('.');
<font color=#0000ff>if</font>(lastDot != -1)
si = si.substring(lastDot + 1);
s += si;
}
<font color=#0000ff>return</font> s;
}
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The class <B>ShowMethodsClean</B>
is quite similar to the previous <B>ShowMethods</B>, except that it takes the
arrays of <B>Method</B> and <B>Constructor</B> and converts them into a single
array of <B>String</B>. Each of these <B>String</B> objects is then passed
through<B> StripQualifiers.Strip( )</B> to remove all the method
qualification. As you can see, this uses the <B>StreamTokenizer</B> and
<B>String</B> manipulation to do its work.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">This tool can be a real time-saver
while you’re programming, when you can’t remember if a class has a
particular method and you don’t want to go walking through the class
hierarchy in the online documentation, or if you don’t know whether that
class can do anything with, for example, <B>Color</B> objects.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Chapter 17 contains a GUI version
of this program so you can leave it running while you’re writing code, to
allow quick
lookups.</FONT><A NAME="_Toc375545411"></A><A NAME="_Toc408018651"></A><BR></P></DIV>
<A NAME="Heading361"></A><FONT FACE = "Verdana"><H2 ALIGN="LEFT">
Summary<BR><A NAME="Index1435"></A></H2></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">RTTI allows you to discover type
information from an anonymous base-class handle. Thus, it’s ripe for
misuse <A NAME="Index1436"></A>by the novice since it might make sense before
polymorphic method calls do. For many people coming from a procedural
background, it’s difficult not to org
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -