"(Reflection) Enables Java code to discover information about the fields, methods and constructors of loaded classes, and to use reflected fields, methods, and constructors to operate on their underlying counterparts on objects, within security restrictions. The API accommodates applications that need access to either the public members of a target object (based on its runtime class) or the members declared by a given class." |
This program assumes that the name of the method as well as the types of arguments in the formal argument list are known.
A test class named TstCls is defined which contains two methods named setFlds() and showFlds(). As you might expect, the setFlds() method is used to set values into the fields of an object of the class, and the showFlds() method displays those values.
The TstCls class has two instance variables. One is of type String and the other is of type Date.
An object of type TstCls is instantiated. The getClass() method is applied to this object to create an object of the Class class named theClass.
An array of Class objects is instantiated such that each of the elements in the array is a Class object that matches the class (type) of a corresponding item in the formal argument list of the method of interest. The method of interest is named "setFlds".
The getMethod() method of the Class class is then used in conjunction with the Class object named theClass and the name of the method of interest (as a String) and the array of class objects to create an object of type Method named theMethod that represents the method of interest.
An array of Object objects is instantiated and populated such that each of the elements in the array represents a parameter to be passed to the method of interest when it is invoked. Note that this must be an array of Object objects, and not an array of Class objects.
Then the invoke() method of the Method class is invoked on the object of type Method, named theMethod, passing a reference to theObj and the array of parameters. This causes the method of interest to be invoked on the object named theObj with the elements of the array being passed as parameters.
Note that the object of type Method is a generic representation of the method of interest which could be used to invoke that method on any object of that type. This is demonstrated later.
Finally, a conventional invocation of the showFlds() method on the object named theObj is executed to display the current values of the instance variables in the object named theObj to confirm that the setFlds() method was actually invoked in the roundabout manner described above.
After this, another object of the same type is instantiated and the Method object is used to invoke the same method on the new object, passing a different set of parameters.
This demonstrates that the Method object is a generic representation of the method of interest and can be used to invoke the method of interest on any object of the same type without any requirement to regenerate the Method object.
A large number of exceptions can be thrown so there is a correspondingly large number of catch blocks at the end of the program to deal with them.
Later on we will provide some examples to show how this may be useful.
This program was tested using JDK 1.1.3 under Win95.
The output from the program is shown in the full program listing later in the lesson.
//Define a test class class TstCls{ String strFld; Date dteFld; //-----------------------------------------------------// public void setFlds(String strFld, Date dteFld){ this.strFld = strFld; this.dteFld = dteFld; }//end setFlds //-----------------------------------------------------// public void showFlds(){ System.out.println(strFld); System.out.println(dteFld); }//end showFlds //-----------------------------------------------------// }//end TstCls |
In fact, the entire remainder of the program is contained in the main() method of that class.
We will break this main() method up and discuss it in parts. The whole thing is enclosed in a try block which we will ignore.
Initially, we will instantiate an object of our test class, and apply
the getClass() method to that object to obtain an object of type
Class which we will reference with a reference variable named theClass.
TstCls theObj = new TstCls(); Class theClass = theObj.getClass(); |
We accomplish this with the following code fragment, assigning the array
to the reference variable named theParams. Note that we are not
simply instantiating new objects of the String and Date classes.
Rather, we are using those new instances to create new instances of the
Class class that represent those classes.
Class[] theParams = new Class[2]; theParams[0] = new String().getClass(); theParams[1] = new Date().getClass(); |
Recall that because of method overloading, the class may contain many methods having this same name, but it can only contain one method having both the name and the argument list specified.
Note that there are several similar-sounding methods of the Class
class that will create Method objects. This particular one will
only create Method objects for public methods.
Method theMethod = theClass.getMethod("setFlds",theParams); |
The methodology for passing the parameters is to instantiate an array of type Object where each of the elements in the array is of the correct type and of the correct value to qualify as parameters to the method. Note that this is an array of type Object and is not an array of type Class.
Objects of type Object can, and in this case, should contain data. On the other hand, objects of type Class represent classes and do not contain data in the sense that we normally use the word data (I'll probably get called to task for this statement).
The following code fragment instantiates and populates an object of
type Object with the first element being a String object
and the second element being a Date object.
Object[] setParams = new Object[2]; setParams[0] = "One Object"; setParams[1] = new Date(); |
At this point, the Method object referred to as theMethod represents a method having a specific name and a specific formal argument list.
We will invoke the invoke() method on theMethod.
The purpose is to invoke another method having the name and a formal argument list represented by our Method object referred to as theMethod.
We will pass to the invoke() method a reference to the object that contains the method of interest.
We will also pass an array of type Object that contains the parameters that we want to pass to the method in that object that we are invoking..
Look this code over very carefully and make certain that you understand
it. This is how the invoke() method works, and is similar to some
other methods in the reflection API.
theMethod.invoke(theObj,setParams); |
We invoke the invoke() method on that object to invoke a method having that signature. To cause it to invoke the method on the correct object, we pass a reference to the object as a parameter to the invoke() method. In other words, if many different objects existed within the scope of our code having methods with the same signature, we could use the same Method object to invoke that method on any of those objects.
Finally, in order to pass the necessary parameters to the method, we instantiate and populate an array of type Object containing the necessary object references to satisfy the required parameters.
If the formal argument list contains arguments of primitive types, we must wrap those primitive values in the standard Java wrappers for the specified type when we construct our array of objects. They will be automatically unwrapped and used when the method is invoked.
The above code should have cause some specific values to be set into
the instance variables of the object on which the method was invoked. Following
this, we use a conventional method invocation approach to invoke the showFlds()
method on the object so that we can inspect those values and confirm that
they were properly set.
theObj.showFlds(); //display new state of object |
TstCls anotherObj = new TstCls(); setParams[0] = "A Different Object"; setParams[1] = new Date(); theMethod.invoke(anotherObj,setParams); anotherObj.showFlds(); //display new state of object |
As indicated earlier, this program was designed for clarity, so that you can see the basic mechanics of using the invoke() method without complicating things by trying to make it do something useful.
The next lesson will apply the invoke() method to a real world situation and develop a relatively sophisticated event-forwarding smart adapter class with built-in event filtering capability.
.
/*File Reflections04.java Copyright 1998, R.G.Baldwin The purpose of this program is to demonstrate the invoke() method of the java.lang.reflect.Method class using a very simple example program. More complicated programs which illustrate some of the benefits will be presented later. This program was tested using JDK 1.1.3 under Win95. The output from the program is shown below. One Object Tue Jan 06 15:08:01 CST 1998 A Different Object Tue Jan 06 15:08:02 CST 1998 **********************************************************/ import java.lang.reflect.*; import java.util.*; //=======================================================// //Define a test class class TstCls{ String strFld; Date dteFld; //-----------------------------------------------------// public void setFlds(String strFld, Date dteFld){ this.strFld = strFld; this.dteFld = dteFld; }//end setFlds //-----------------------------------------------------// public void showFlds(){ System.out.println(strFld); System.out.println(dteFld); }//end showFlds //-----------------------------------------------------// }//end TstCls //=======================================================// class Reflections04 { public static void main(String[] args) { try{ //Instantiate an object of the test class TstCls theObj = new TstCls(); //Create a Class object for the test class Class theClass = theObj.getClass(); //Create an array of Class objects which matches // the known formal argument list of the method // of interest. Class[] theParams = new Class[2]; theParams[0] = new String().getClass(); theParams[1] = new Date().getClass(); //Use the name of the method and the array describing // the formal argument list to create an object of // type Method that represents the method of interest Method theMethod = theClass.getMethod("setFlds",theParams); //Create an array of Object objects that matches // the known formal argument list of the method of // interest. Populate this array with parameter // values to be passed to the method. Note that // this is an Object array and not a Class array. Object[] setParams = new Object[2]; setParams[0] = "One Object"; setParams[1] = new Date(); //Use the Method object and the array of parameter // objects to invoke the method of interest. theMethod.invoke(theObj,setParams); //Use the conventional approach to invoke another // method on the same object to demonstrate that // the setFlds() method was properly invoked. theObj.showFlds(); //display new state of object //Instantiate another object of the same type and // use the existing Method object to invoke the same // method on it, passing different parameters. TstCls anotherObj = new TstCls(); setParams[0] = "A Different Object"; setParams[1] = new Date(); theMethod.invoke(anotherObj,setParams); anotherObj.showFlds(); //display new state of object }//end try block //Deal with all the possible exceptions here catch(SecurityException e){System.out.println(e);} catch(NoSuchMethodException e){System.out.println(e);} catch(IllegalAccessException e){System.out.println(e);} catch(IllegalArgumentException e){ System.out.println(e);} catch(InvocationTargetException e){ System.out.println(e);} }//end main() }//end Reflections04 |