Bruce Eckel’s Thinking in Java | Contents | Prev | Next |
11 introduced the Java 1.1 concept of reflection
and used that feature to look up methods for a particular class – either
the entire list of methods or a subset of those whose names match a keyword you
provide. The magic of this is that it can automatically show you
all
the methods for a class without forcing you to walk up the inheritance
hierarchy examining the base classes at each level. Thus, it provides a
valuable timesaving tool for programming: because the names of most Java method
names are made nicely verbose and descriptive, you can search for the method
names that contain a particular word of interest. When you find what you think
you’re looking for, check the online documentation.
by Chapter 11 you hadn’t seen the AWT, so that tool was developed as a
command-line application. Here is the more useful GUI version, which
dynamically updates the output as you type and also allows you to cut and paste
from the output:
//: DisplayMethods.java // Display the methods of any class inside // a window. Dynamically narrows your search. import java.awt.*; import java.awt.event.*; import java.applet.*; import java.lang.reflect.*; import java.io.*; public class DisplayMethods extends Applet { Class cl; Method[] m; Constructor[] ctor; String[] n = new String[0]; TextField name = new TextField(40), searchFor = new TextField(30); Checkbox strip = new Checkbox("Strip Qualifiers"); TextArea results = new TextArea(40, 65); public void init() { strip.setState(true); name.addTextListener(new NameL()); searchFor.addTextListener(new SearchForL()); strip.addItemListener(new StripL()); Panel top = new Panel(), lower = new Panel(), p = new Panel(); top.add(new Label("Qualified class name:")); top.add(name); lower.add( new Label("String to search for:")); lower.add(searchFor); lower.add(strip); p.setLayout(new BorderLayout()); p.add(top, BorderLayout.NORTH); p.add(lower, BorderLayout.SOUTH); setLayout(new BorderLayout()); add(p, BorderLayout.NORTH); add(results, BorderLayout.CENTER); } class NameL implements TextListener { public void textValueChanged(TextEvent e) { String nm = name.getText().trim(); if(nm.length() == 0) { results.setText("No match"); n = new String[0]; return; } try { cl = Class.forName(nm); } catch (ClassNotFoundException ex) { results.setText("No match"); return; } m = cl.getMethods(); ctor = cl.getConstructors(); // Convert to an array of Strings: n = new String[m.length + ctor.length]; for(int i = 0; i < m.length; i++) n[i] = m[i].toString(); for(int i = 0; i < ctor.length; i++) n[i + m.length] = ctor[i].toString(); reDisplay(); } } void reDisplay() { // Create the result set: String[] rs = new String[n.length]; String find = searchFor.getText(); int j = 0; // Select from the list if find exists: for (int i = 0; i < n.length; i++) { if(find == null) rs[j++] = n[i]; else if(n[i].indexOf(find) != -1) rs[j++] = n[i]; } results.setText(""); if(strip.getState() == true) for (int i = 0; i < j; i++) results.append( StripQualifiers.strip(rs[i]) + "n"); else // Leave qualifiers on for (int i = 0; i < j; i++) results.append(rs[i] + "n"); } class StripL implements ItemListener { public void itemStateChanged(ItemEvent e) { reDisplay(); } } class SearchForL implements TextListener { public void textValueChanged(TextEvent e) { reDisplay(); } } public static void main(String[] args) { DisplayMethods applet = new DisplayMethods(); Frame aFrame = new Frame("Display Methods"); aFrame.addWindowListener( new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } }); aFrame.add(applet, BorderLayout.CENTER); aFrame.setSize(500,750); applet.init(); applet.start(); aFrame.setVisible(true); } } class StripQualifiers { private StreamTokenizer st; public StripQualifiers(String qualified) { st = new StreamTokenizer( new StringReader(qualified)); st.ordinaryChar(' '); } public String getNext() { String s = null; try { if(st.nextToken() != StreamTokenizer.TT_EOF) { switch(st.ttype) { case StreamTokenizer.TT_EOL: s = null; break; case StreamTokenizer.TT_NUMBER: s = Double.toString(st.nval); break; case StreamTokenizer.TT_WORD: s = new String(st.sval); break; default: // single character in ttype s = String.valueOf((char)st.ttype); } } } catch(IOException e) { System.out.println(e); } return s; } public static String strip(String qualified) { StripQualifiers sq = new StripQualifiers(qualified); String s = "", si; while((si = sq.getNext()) != null) { int lastDot = si.lastIndexOf('.'); if(lastDot != -1) si = si.substring(lastDot + 1); s += si; } return s; } } ///:~
things you’ve seen before. As with many of the GUI programs in this book,
this is created to perform both as an application and as an applet. Also, the
StripQualifiers
class is exactly the same as it was in Chapter 11.
GUI contains a
TextField
name
in
which you can enter the fully-qualified class name you want to look up, and
another one,
searchFor,
in which you can enter the optional text to search for within the list of
methods. The
Checkbox
allows you to say whether you want to use the fully-qualified names in the
output or if you want the qualification stripped off. Finally, the results are
displayed in a
TextArea.
notice that there are no buttons or other components by which to indicate that
you want the search to start. That’s because both of the
TextFields
and the
Checkbox
are monitored by their listener objects. Whenever you make a change, the list
is immediately updated. If you change the text within the
name
field,
the new text is captured in
class
NameL
.
If the text isn’t empty, it is used inside Class.forName( )
to try to look up the class. As you’re typing, of course, the name will
be incomplete and
Class.forName( )
will fail, which means that it throws an exception. This is trapped and the
TextArea
is set to “No match”. But as soon as you type in a correct name
(capitalization counts),
Class.forName( )
is successful and
getMethods( )
and
getConstructors( )
will return arrays of
Method
and
Constructor
objects, respectively. Each of the objects in these arrays is turned into a
String
via
toString( )
(this produces the complete method or constructor signature) and both lists are
combined into
n,
a single
String
array. The array
n
is a member of
class
DisplayMethods
and is used in updating the display whenever
reDisplay( )
is called.
you change the
Checkbox
or
searchFor
components, their listeners simply call
reDisplay( ).
reDisplay( )
creates a temporary array of
String
called
rs
(for “result set”). The result set is either copied directly from
n
if there is no
find
word, or conditionally copied from the
Strings
in
n
that contain the
find
word. Finally, the
strip
Checkbox
is interrogated to see if the user wants the names to be stripped (the default
is “yes”). If so,
StripQualifiers.strip( )
does the job; if not, the list is simply displayed.
init( ),
you might think that there’s a lot of busy work involved in setting up
the layout. In fact, it is possible to lay out the components with less work,
but the advantage of using
BorderLayouts
this way is that it allows the user to resize the window and make – in
particular – the
TextArea
larger, which means you can resize to allow you to see longer names without
scrolling.