Calling a method via reflection in Java: details
On the previous page, we introduced the Java reflection API
and showed a simple example of calling the String.length() method on a
given string via reflection. On this page, we follow that example up with some
further observations and common variations.
Class lookup
In this case, we looked up the class "manually" via Class.forName().
However, if the class name is fixed and resolvable at compile time,
as it might well be in various typical cases,
the compiler actually allows us to write the following shorthand:
Method lenMethod = String.class.getDeclaredMethod(...);
Method parameters
A method is defined not only by its name, but also by the list of parameters
it can take. As you're probably aware, Java permits polymorphism: that is,
various methods can exist on the same class provided that they have different
parameter lists. Therefore, when we retrieve a Method object, we must
supply not just the name, but also a list of parameter types. The list of paramter
types is supplied as an array of Class objects, although in the case of a
method like String.length() that takes no parameters, the array is empty.
When we do have to supply a Class object representing a parameter type,
using the above compiler shortcut for looking up the Class object can be useful.
For example, we could retrieve String.endsWith()
method (which takes a single String parameter) as follows:
String.class.getDeclaredMethod("endsWith",
new Class[] { String.class });
In the invoke() call, we would then supply the string in question inside
the object array (which was empty in the above example):
boolean b = (Boolean) lenMethod.invoke(stringObj,
new Object[] {});
Dealing with primitive parameters
Using reflection to call methods that take primitive parameters can be slightly
confusing at first. Let's take the example of calling the two-parameter
version of String.substring() via reflection. We might have expected
to perform the method lookup as follows:
// This is actually WRONG!
String.class.getDeclaredMethod("substring",
new Class[] { Integer.class, Integer.class });
Well, if you try this, you'll find that a NoSuchMethodException is
thrown. Why? Well, because the above code is looking for a method that takes two
Integer objects as its parameters, not to int primitives!
How do we fix this? Well, it turns out that the solution is the little-used
.TYPE field that exists on the various wrapper classes (Integer.TYPE,
Long.TYPE etc). These fields contain a reference to a special Class
object that represents the primitive type. So the correct version of
the above line would be:
String.class.getDeclaredMethod("substring",
new Class[] { Integer.TYPE, Integer.TYPE });
On the other hand, when we invoke the method via Method.invoke(),
we pass in a wrapper object for the primitive values:
substringMethod.invoke(stringObj, new Object[] {
new Integer(0), new Integer(4)
});
However in practice, as of Java 5, the compiler allows us to write the following:
substringMethod.invoke(stringObj, new Object[] {0, 4});
However, note that this is essentially a compiler trick; what actually gets placed
into the array are obviously corresponding Integer objects.
If you enjoy this Java programming article, please share with friends and colleagues. Follow the author on Twitter for the latest news and rants.
Editorial page content written by Neil Coffey. Copyright © Javamex UK 2021. All rights reserved.