Introduction to the Java reflection API
In Java and various other languages,
reflection is the technique of a program "looking in on itself".
With the reflection API you can perform tasks such as enumerate all the fields of a
given class, or call a method by a name supplied at runtime.
A typical way of using the reflection API involves the following steps:
- get a Class object representing the class with a particular name;
- from that Class, request a Method object representing
the method with a particular name and parameter types;
- call the method in question via the Method object.
There are variations on this theme depending on our exact purpose. For example,
we could ask for an object representing a particular field (static or instance
variable) of a given class and use this to read/write the value in question. We could
also request a list of all the fields or methods on a given class which can
be useful, for example, in some profiling applications.
When to use reflection?
Essentially, reflection is useful in a variety of cases when it's not convenient
or possible to hard-code a given method call or field access into the code. Some typical
uses include:
- to allow "pluggable" archtectures, where a given class name or method
name is configured in a file or otherwise determined while the
program is running;
- cases where it's easier programmatically to pass/store a method name
rather than an object;
- profiling applications, where for a variety of reasons you need to
list/query the contents and definition of a given class.
Example reflection code
Starting with a simple case, the following code shows how to call the String.length()
method on a string using reflection (exception handling code is ommitted for clarity):
String stringObj = "This is a string";
Class clz = Class.forName("java.lang.String");
Method lenMethod = clz.getDeclaredMethod("length",
new Class[] {});
int strlen = (Integer) lenMethod.invoke(stringObj,
new Object[] {});
In principle, the steps are relatively straightforward. Firstly, we retrieve the
Class object corresponding to the class whose method we wish to call.
Then, we call getDeclaredMethod, passing in the name of the method,
plus an array of parameter types, and are returned a corresponding Method
object. If no such method exists, then a NoSuchMethodException is
thrown. Finally, we call invoke(), passing in the object on which
we wish to call the given method (which could be null in the case of
a static method) and an array of objects representing the parameters (or an empty
array if there are no paramters as in the String.length() method).
Note that when we call invoke() on the given Method object,
we are passed the method's return value as an Object. In this case, we know
that the specific return type is a primitive int, and we will be returned
a corresponding Integer wrapper object by the invoke() method
(because this method must always return an Object). So we safely cast the
return value to an Integer. In addition, Java 5 onwards allows us to
directly assign this Integer object to a primitive int variable
(a process called "auto-unboxing")— the compiler will automatically insert
a call to intValue() for us.
Next: further observations/variations on reflective method calls
Following on from the above basic template for making a reflexive call,
on the next page we look at further details
of calling a method via reflection.
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.