In programming terms, reflection is a feature that allows you to see the internal composition of a program—everything from its variables to its method declarations. As its name indicates, the Java Reflection API enables this functionality in Java.
The Java Reflection API provides insight into the classes, interfaces, and objects in a given Java Virtual Machine (JVM). Developers commonly use the API to accomplish the following tasks, which explains why it is so often used to develop tools such as debuggers and Integrated Development Environments (IDEs):
- Determine the class of an object.
- Get information about a class’s modifiers, fields, methods, constructors, etc.
- Get information about an interface’s constants and method declarations.
- Create an instance of a class whose name is not known until runtime, but rather available at design time or provided as a runtime parameter.
- Get and set the value of an object’s field, even if the field name is unknown to your program until runtime.
- Invoke a method on an object, even if the method is not known until runtime.
Using Reflection to Retrieve Class Behavior
To understand how you can use reflection to ascertain a class’s behavior, consider the simple example of an Employee class:public class EmployeeCompiling the Modifier classes and executing the AnalyzeClass produces the following output:
{
public String empNum;
public String empName;public Employee()
{
this( “1”, “King”);
}public Employee(String empNum, String empName)
{
empNum = empNum;
empName = empName;
}public String toString()
{
return “Employee Details: EmpNumber: ” + empNum + “,
EmpName: “+ empNum;
}
}import java.lang.reflect.Modifier;
public class AnalyzeClass
{
public static void main(String[] args)
{Employee employee = new Employee();
Class klass = employee.getClass();
System.out.println( “Class name: ” + klass.getName());
System.out.println(
“Class super class: ” + klass.getSuperclass());int mods = klass.getModifiers();
System.out.println(
“Class is public: ” + Modifier.isPublic(mods));
System.out.println(
“Class is final: ” + Modifier.isFinal(mods));
System.out.println(
“Class is abstract: ” + Modifier.isAbstract(mods));}
}
Class name: EmployeeThis is basically an extract of the Employee class, so you are able to retrieve all the properties that it has. Need more convincing? Consider another example involving a Method class:
Class super class: class java.lang.Object
Class is public: true
Class is final: false
Class is abstract: false
import java.lang.reflect.*;When you compile this code and invoke it with an argument of a known class…public class DumpMethods {
public static void main(String args[])
{
try {
Class c = Class.forName(args[0]);
Method m[] = c.getDeclaredMethods();
for (int i = 0; i < m.length; i++)
System.out.println(m[i].toString());
}
catch (Throwable e) {
System.err.println(e);
}
}
}
java DumpMethods java.util.Stack…You receive the following result:
public synchronized java.lang.Object java.util.Stack.pop()The preceding output lists all the methods of the java.util.Stack class. Method is a class in java.lang.reflect, which is responsible for yielding this result.
public java.lang.Object java.util.Stack.push(java.lang.Object)
public boolean java.util.Stack.empty()
public synchronized java.lang.Object java.util.Stack.peek()
public synchronized int java.util.Stack.search(java.lang.Object)
Using Reflection to Retrieve Attributes
A class has other entities besides the ones you have seen so far. What about variables, for example? You can use reflection to get a detailed output of these entities as well. Here is another example using a Field class:import java.lang.reflect.*;When you compile this and execute it with an argument of Employee…public class DumpFields {
public static void main(String args[])
{
try {
Class c = Class.forName(args[0]);
Field[] fields = c.getFields();
for (int i = 0; i < fields.length; i++)
System.out.println(fields[i].toString());
}
catch (Throwable e) {
System.err.println(e);
}
}
}
java DumpFields Employee…You receive the following output:
public java.lang.String Employee.empNumThis result lists all the fields/attributes that belong to the class.
public java.lang.String Employee.empName
Using Reflection to Retrieve Constructors
This example of a Constructor class will help complete your understanding of the various constructors available, as well as how to use them.import java.lang.reflect.*;When you compile this and execute it with an argument of Employee…public class DumpConstructors {
public static void main(String args[])
{
try {
Class c = Class.forName(args[0]);
Constructor[] constructor = c.getConstructors();
for (int i = 0; i < constructor.length; i++)
{
System.out.println(constructor[i].toString());
//To print the parameter types
Class pvec[] = constructor[i].getParameterTypes();
for (int j = 0; j < pvec.length; j++)
System.out.println(“param #” + j + ” ”
+ pvec[j]);
}}
catch (Throwable e) {
System.err.println(e);
}
}
}
javac DumpConstructors Employee…You receive the following result:
public Employee(java.lang.String,java.lang.String)Analyzing the result, you will find that the Employee class has two constructors. The first one is a parameterized constructor (you can see the parameter types also). The second does not take any parameters and the result is self-explanatory.
param #0 class java.lang.String
param #1 class java.lang.String
public Employee()
Using Reflection to Execute Class Methods at Runtime
Suppose you have a class and want to use it at runtime. The code below shows how you can load the class and execute a desired method at runtime. The assumption here is that the method’s name is setProperties and it takes an argument of type java.util.Properties.Class newClass = null;These utilities allow an IDE developer to accommodate Java as a supported programming language quite easily.Method getInstanceMethod = null;
Properties prop = new Properties();
prop.put(“argName”, “argValue”);
try
{
Object obj = newClass.newInstance();
getInstanceMethod = newClass.getMethod(“setProperties”,
new Class[]{new Properties().getClass()});}
catch (Exception ex)
{
//Exception in loading Class:” + ex.getMessage();
}
A Word of Caution
You have seen the advantages of using the Java Reflection API, but you must understand the disadvantages of reflection as well. For example, debugging will be a nightmare if you don’t understand the process well. It is best to use reflection to solve a given problem only when you have weighed it against other available mechanisms.
Code Download