If you just wanted to find fields
and
methods in one particular class, you wouldn’t need this; you
could simply create an instance of the class using
new
and refer to its fields and methods directly.
This allows you to find methods and fields in any class, even classes
that have not yet been written! Given a class object created as in
Section 25.2, you can obtain a list of constructors,
a list of methods, or a list of fields. The method
getMethods( )
lists the methods available for a given class as an array of
Method
objects. Since constructor methods are
treated specially by Java, there is also a getConstructors( )
method,
which returns an array of Constructor
objects.
Even though “class” is in the package
java.lang
, the Constructor
,
Method
, and Field
objects it
returns
are in
java.lang.reflect
, so you need an import of this
package. The ListMethods
class (Example 25-1) shows how to do this.
Example 25-1. ListMethods.java
import java.lang.reflect.*; /** * List the Constructors and methods */ public class ListMethods { public static void main(String[] argv) throws ClassNotFoundException { if (argv.length == 0) { System.err.println("Usage: ListMethods className"); return; } Class c = Class.forName(argv[0]); Constructor[] cons = c.getConstructors( ); printList("Constructors", cons); Method[] meths = c.getMethods( ); printList("Methods", meths); } static void printList(String s, Object[] o) { System.out.println("*** " + s + " ***"); for (int i=0; i<o.length; i++) System.out.println(o[i].toString( )); } }
For example, you could run Example 25-1 on a class
like java.lang.String
and get a fairly lengthy list of methods;
I’ll only show part of the output so you can see what it looks
like:
> java ListMethods java.lang.String *** Constructors *** public java.lang.String( ) public java.lang.String(java.lang.String) public java.lang.String(java.lang.StringBuffer) public java.lang.String(byte[]) // and many more... *** Methods *** public static java.lang.String java.lang.String.copyValueOf(char[]) public static java.lang.String java.lang.String.copyValueOf(char[],int,int) public static java.lang.String java.lang.String.valueOf(char) // and more valueOf( ) forms... public boolean java.lang.String.equals(java.lang.Object) public final native java.lang.Class java.lang.Object.getClass( ) // and more java.lang.Object methods... public char java.lang.String.charAt(int) public int java.lang.String.compareTo(java.lang.Object) public int java.lang.String.compareTo(java.lang.String)
You can see that this could be extended (almost literally) to write a
BeanMethods
class that would list only the set/get
methods defined in a JavaBean (see Section 23.8).
Alternately, you can find a particular method and invoke it, or find
a particular field and refer to its value. Let’s start by
finding a given field, since that’s the easiest. Example 25-2 is code that, given an
Object
and the name of a field, finds the field
(gets a Field
object), then retrieves and prints
the value of that Field
as an
int
.
Example 25-2. FindField.java
import java.lang.reflect.*; import java.util.*; /** This class shows using Reflection to get a field from another class. */ public class FindField { public static void main(String[] unused) throws NoSuchFieldException, IllegalAccessException { // Create instance of FindField FindField gf = new FindField( ); // Create instance of target class (YearHolder defined below). Object o = new YearHolder( ); // Use gf to extract a field from o. System.out.println("The value of 'currentYear' is: " + gf.intFieldValue(o, "currentYear")); } int intFieldValue(Object o, String name) throws NoSuchFieldException, IllegalAccessException { Class c = o.getClass( ); Field fld = c.getField(name); int value = fld.getInt(o); return value; } } /** This is just a class that we want to get a field from */ class YearHolder { /** Just a field that is used to show getting a field's value. */ public int currentYear = Calendar.getInstance( ).get(Calendar.YEAR); }
What if we need to find a method? The simplest way is to use the
methods getMethod( )
and
invoke( )
to do the deed. But this is not
altogether trivial. Suppose that somebody gives us a
reference to an
object. We don’t know its class, but have been told that it
should have this method:
public void work(String s) { }
We wish to invoke work( )
. To find the method, we
must make an array of Class
objects, one per item
in the calling list. So in this case, we make an array containing
only a reference to the class object for String
.
Since we know the name of the class at compile time, we’ll use
the shorter invocation String.class
instead of
Class.forName( )
. This, plus the name of the
method as a string, gets us entry into the getMethod( )
method of the Class
object. If this
succeeds, we have a Method
object. But guess what?
In order to invoke the method, we have to construct yet another
array, this time an array of Object
references,
actually containing the data to be passed to the invocation. We also,
of course, need an instance of the class in whose context the method
is to be run. For this demonstration class, we need to pass only a
single string, as our array consists only of the string. Example 25-3 is the code that finds the method and invokes
it.
Example 25-3. GetMethod.java
import java.lang.reflect.*; /** This class is just here to give us something to work on, * with a println( ) call that will prove we got here. */ class X { public void work(String s) { System.out.println("Working on "" + s + """); } } /** * Get a given method, and invoke it. */ public class GetMethod { public static void main(String[] argv) { try { Class clX = X.class; // or Class.forName("X"); // To find a method we need the array of matching Class types. Class[] argTypes = { String.class }; // Now find a Method object for the given method. Method worker = clX.getMethod("work", argTypes); // To INVOKE the method, we need its actual arguments, as an array. Object[] theData = { "Chocolate Chips" }; // The obvious last step: invoke the method. worker.invoke(new X( ), theData); } catch (Exception e) { System.err.println("Invoke( ) failed: " + e); } } }
Not tiny, but still not bad. In most programming languages, you couldn’t do that in the 40 lines it took us here.
A word of caution: when the arguments to a method are of a
primitive
type such as int
, you do not pass
Integer.class
into getMethod( )
. Instead, you must use the class object representing the
primitive type int
. The easiest way to find this
class is in the Integer
class, as a
public constant named
TYPE
, so you’d pass
Integer.TYPE
. The same is true for all the
primitive types; for each, the corresponding
wrapper class has the primitive
class
referred to as
TYPE
.
3.145.179.35