Available since Java 1.1, the Reflection API allows a Java application to get the definition of classes and operate on them at runtime without having them available at compile time. That allows the easy creation of applications that wouldn’t otherwise be possible. For example, you can use the Reflection API to inspect objects, browse classes, and create callback methods, such as event handlers, without extending a specific class or implementing an interface.
The Java Reflection API is composed of the classes in the package java.lang.reflect and methods of java.lang.class. Invoking such methods on a Class object, you can get the complete definition of the class it represents, such as its constructors, methods, and fields. These are returned as instances of the classes in the package java.lang.reflect. Each class provides a suitable API that lets you get any information about the entity it represents, such as the name and type of a field and the parameters of a constructor or method. You can also manipulate the fields or call constructors and methods, subject to the language and Java Virtual Machine (JVM) access restrictions.
The only way to get access to the class definition is through appropriate methods of Class. So you must first get the Class object that represents the class you are interested in. There are several ways of doing that. One way is to call the static method forName(String) of Class, specifying the fully qualified name of the class you want. If you have an instance of the class, you can also call its getClass() method.
Using the Reflection API. you can create new instances of classes, much like the Class method newInstance(). However, the Reflection API allows you to select which constructor to call.
First, you must get the definition of the constructor you want, which is represented by an instance of the class java.lang.reflect.Constructor. You can get the definition of a constructor by calling the method Class.getConstructor(Class), passing an array of Class objects that represent the parameter types of the desired constructor. Although primitive types are not classes, Java provides correspondent Class objects to represent them, as shown in Table A.
The getConstructor(Class) method returns just public constructors of the class. To get the definition of any constructor, including package, private, and protected, use the method Class.getDeclaredConstructor(Class). You can also get a list of all constructors (Class.getDeclaredConstructors()) or just the public ones (Class.getConstructors()).
Once you have the Constructor object corresponding to the desired constructor, all you have to do is call its newInstance(Object) method, passing the parameters of the constructor as an array of objects of the types expected by the constructor. Objects must encapsulate values of primitive types, as shown in Table B.
Using the Constructor API, you can also get any information about the constructor it represents, like its parameters, exception types, and the constructor modifiers.
Much as you can invoke constructors of a given class, you can invoke methods on objects. First, you must get their definition through one of the methods Class.getMethod(String,Class) or Class.getDeclaredMethod(String,Class). The first parameter is the method’s name and the second is an array of Class objects representing the types of its parameters.
Getmethod returns the public method that matches the parameters provided, whether it is declared by the class or inherited, while getDeclaredMethod returns just those declared by the class (including package, protected, and private).
You can also get a list of all public methods of the class, including those inherited (Class.getMethods()), or all methods declared by the class, including package, protected, and private (Class.getDeclaredMethods()).
In any case, the method’s definition is represented by an instance of the java.lang.reflect.Method class. Using its API you can get any information you want about the method it represents. You can also invoke the method on an object using Method.invoke(Object,Object).
The first argument is the object whose method you want to call (ignored if the method is static). The second is an array of objects corresponding to the parameters to be passed to the method. The same encapsulation rules presented in Table B apply regarding primitive values.
You can also get the value of fields and change them using the Reflection API. The principle is the same—that is, get the definition of the field you want using one of the methods Class.getField(String) or Class.getDeclaredField(String), passing the name of the desired field as the parameter. The methods operate the same way as their getMethod and getDeclaredMethod counterparts.
You can get a list of all fields declared by the class through the method Class.getDeclaredFields() or just the public fields (including inherited ones) using the method Class.getFields().
Fields are represented by instances of the class java.lang.reflect.Field. Once you have an instance of the Field class, you can get the value of the field it represents using the method Field.get(Object), passing as the parameter the object whose field you want to get (ignored if the field is static). If the field is of primitive type, it is encapsulated in an object according to Table B.
Field provides convenient methods to get the value of fields of primitive types, as shown in Table C. The Reflection API applies widening conversion to change the field’s actual type to the value returned by the method.
To change the value of a field, use the method Field.set(Object,Object). The first argument is the object to set the field, and the second is the value to set, provided as an object of the same type as the field’s. If the field is of a primitive type, the value must be encapsulated according Table B. Convenient methods to set the value of fields of primitive types are also provided in Table D.
Access to the Reflection API is subject to the Java security policies. The default policy for applications is to grant access to any information of any class. However, the use of reflected constructors, methods, and fields are restricted by the standard Java language access control; that is, a class can use only public members, package members of the same package, and inherited protected members.
Applications can override the default access control by calling the method setAccessible(boolean) on the reflected constructor, field, or method desired, passing true as the parameter. Notice, however, that this is available starting only with Java 1.2. The ability to call setAccessible, in turn, is controlled by the permission ReflectPermission, with the target suppressAccessChecks.
The Reflection API is an important part of the Java platform because it allows an application to get runtime access to classes and their definitions, opening the door to all sorts of interesting possibilities.
In this article, I presented the basics about the Reflection API. You can learn more by checking the JDK documentation for complete information. In a future article, I will present some techniques made possible by the Reflection API that you can use in your applications.