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:

  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!
  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:

  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.