CODE
Now you'll see how to invoke a method whose
name has been typed into a TextField
.
This is an artificial example of reflection.
In fact few programs really require reflection,
but application builder tools rely heavily
on reflection and introspection (which is
built on top of reflection to support Beans).
You're now going to add two methods
which will be invoked by using
reflection. Given a string
naming a method, a Method
object
will be retrieved and subsequently
invoked with the proper arguments.
In order to support the reflection
classes, add the following package
import statement at the end of
the current list of imports:
import java.lang.reflect.*;
Now have a look at the methods
that will be called based on
TextField
input events or
Choice ItemSelected
events:
First add a paint
method that
draws a rectangle of variable
size:
public void paint(Graphics g) {
g.drawRect(x,y,w,h);
}
Instance variables should be declared
at the top of the class definition
to control the rectangle's size:
public class ChoiceApplet04 extends Applet
{
...
int x,y,w,h;
...
}
The paint
method will be called
automatically to update the applets
frame with the newly drawn rectangle
whenever a repaint
method is called.
This is done inside two new methods
that you must now define:
public void big() {
System.out.println("big()");
x=10; y=50; w=100; h=100;
repaint();
}
public void small() {
System.out.println("small()");
x=10; y=50; w=20; h=20;
repaint();
}
The first draws a big rectangle
the second draws a small one.
You will not be calling these
methods directly, but indirectly
throught the Reflect lookup
mechansism. This is the essence
of last four sections of exercises.
The method which does the lookup
and invocation is called
invoke
:
public void invoke(String mName) {
try {
Method m =
ChoiceApplet04.class.getDeclaredMethod(
mName, null);
m.invoke(this, null);
}
catch (Exception ex) {
System.err.println("no such method: "+mName);
}
}
Given a String, mName
which names the method,
the Class object for
ChoiceApplet04
can call
getDeclaredMethod
to get a Method
object, m
.
To get the applet's class, use:
ChoiceApplet04.class
.
The
getDeclaredMethod
gets two arguments: a String,
naming the method for the
class, and an array of argments.
Essentially you are
the signature of
the desired method in the
call
ChoiceApplet04.class.getDeclaredMethod(mName, null);
Since no arguments are required by either the
big
or small
methods,
null is given as the second argument.
Now that you have the desired Method
object in the variable m
,
you can invoke it as follows:
m.invoke(this, null);
If either the method lookup or the invocation
fails, an exception is thrown in the
try
block. If this
happens, the exception handling code
in the catch
block reports that
"no such method:" exists and prints
the offending method name.
Method names "big" or "small" will
work; any other names will throw
an exception.
Just for tidiness, you'll want to
keep the text displayed in
the TextField
consistent with
the selection in the Choice
component and vice versa. Add
the following code to the
actionPerformed
method of
the inner class handling
events for theTextField
:
if (mName.equals("big") ||
mName.equals("small"))
theChoice.select(mName);
else
theChoice.select("unknown");
Immediatley after this code, add a
statment to call invoke based
on the String now in the TextField
:
invoke(mName);
The same call must be added to the
event handler code for the Choice
component.
The respective listener registration
and event handler definitions look
like this:
theChoice.addItemListener(new ItemListener() {
public void itemStateChanged(ItemEvent e) {
System.out.println(
"ENTER----->theChoice ActionListener");
String mName = (String) e.getItem();
System.out.println("mName: " + mName);
String pString =
e.paramString(); // useful for Debugging
System.out.println("pString: " + pString);
theTextField.setText(mName);
invoke(mName);
System.out.println(
"EXIT------>theChoice ActionListener");
}
});
theTextField.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.out.println(
"ENTER----->theTextField ActionListener");
String mName = e.getActionCommand();
System.out.println("mName: " + mName);
if (mName.equals("big") ||
mName.equals("small"))
theChoice.select(mName);
else
theChoice.select("unknown");
invoke(mName);
System.out.println(
"EXIT------>theTextField ActionListener");
}
});
}
Hopefully that wasn't too bad. Once
you get the hang of inner classes,
events and event listeners, you'll
be on solid ground for programming
JDK 1.1 applications and applets.
Reflection is worth knowing about in
certain situations. As mentioned
if your are building programming
environments and tools that need
to find out the capabilities of
classes at run time, you'll find
Reflection is indespensible. For
typical programs, however, you should focus on the
new event model.
You'll find more detailed examples
of event handlers, inner classes,
reflection, and introspection in
the next four sections starting
with
LINKFILE $NEXTFILE
LINKTEXT Automatically Resized Beans
)
You can use
TestChoiceApplet04.html
to test the applet.
Program Source Code
A makefile
for this lesson automates source code compilation,
JAR file construction, and copying of JAR files to the
appropriate BeanBox directory. You'll have to edit several of the
variables in the makefile to indicate the location of your JDK 1.1
and BDK installation directories.
You may want to look at the final source file for
ChoiceApplet04.java
to verify changes.