Java Reflection Tutorial PDF
Java Reflection Tutorial PDF
Java Reflection Tutorial PDF
Java Reflection makes it possible to inspect classes, interfaces, fields and methods at runtime, without knowing
the names of the classes, methods etc. at compile time. It is also possible to instantiate new objects, invoke
methods and get/set field values using reflection.
Java Reflection is quite powerful and can be very useful. For instance, when mapping objects to tables in a
database at runtime, like Butterfly Persistence does. Or, when mapping the statements in a script language to
method calls on real objects at runtime, like Butterfly Container does when parsing its configuration scripts.
There are already numerous Java Reflection Tutorials on the internet. However, most of them, including Sun's
own Java Reflection tutorial, only scratch the surface of Java Reflection and its possibilities.
This tutorial will get into Java reflection in more depth than most of the tutorials I have seen. It will explain the
basics of Java Reflection including how to work with arrays, annotations, generics and dynamic proxies, and do
dynamic class loading and reloading. It will also show you how to do more specific tasks, like reading all getter
methods of a class, or accessing private fields and methods of a class. This tutorial will also clear up some of
the confusion out there about what Generics information is available at runtime. Some people claim that all
Generics information is lost at runtime. This is not true.
This tutorial describes the version of Java Reflection found in Java 6.
This example obtains the Class object from the class called MyObject. Using the class object the example gets
a list of the methods in that class, iterates the methods and print out their names.
Exactly how all this works is explained in further detail throughout the rest of this tutorial (in other texts).
Class Name
Class Modifies (public, private, synchronized etc.)
Package Info
Superclass
Implemented Interfaces
Constructors
Methods
Fields
Annotations
Plus a lot more information related to Java classes. For a full list you should consult the JavaDoc for
java.lang.Class. This text will briefly touch upon all accessing of the above mentioned information. Some of the
topics will also be examined in greater detail in separate texts. For instance, this text will show you how to
obtain all methods or a specific method, but a separate text will show you how to invoke that method, how to
find the method matching a given set of arguments if more than one method exists with the same name, what
exceptions are thrown from method invocation via reflection, how to spot a getter/setter etc. The purpose of this
text is primarily to introduce the Class object and the information you can obtain from it.
If you don't know the name at compile time, but have the class name as a string at runtime, you can do like this:
String className = ... //obtain class name as string at runtime Class class = Class.forName(className);
When using the Class.forName() method you must supply the fully qualified class name. That is the class
name including all package names. For instance, if MyObject is located in package com.jenkov.myapp then the
fully qualified class name is com.jenkov.myapp.MyObject
The Class.forName() method may throw a ClassNotFoundException if the class cannot be found on the
classpath at runtime.
Class Name
From a Class object you can obtain its name in two versions. The fully qualified class name (including package
name) is obtained using the getName() method like this:
Class aClass = ... //obtain Class object. See prev. section
String className = aClass.getName();
If you want the class name without the pacakge name you can obtain it using the getSimpleName() method,
like this:
Class aClass
= ... //obtain Class object. See prev. section
String simpleClassName = aClass.getSimpleName();
Modifiers
You can access the modifiers of a class via the Class object. The class modifiers are the keywords "public",
"private", "static" etc. You obtain the class modifiers like this:
Class aClass = ... //obtain Class object. See prev. section
int modifiers = aClass.getModifiers();
The modifiers are packed into an int where each modifier is a flag bit that is either set or cleared. You can
check the modifiers using these methods in the class java.lang.reflect.Modifier:
Modifier.isAbstract(int modifiers)
Modifier.isFinal(int modifiers)
Modifier.isInterface(int modifiers)
Modifier.isNative(int modifiers)
Modifier.isPrivate(int modifiers)
Modifier.isProtected(int modifiers)
Modifier.isPublic(int modifiers)
Modifier.isStatic(int modifiers)
Modifier.isStrict(int modifiers)
Modifier.isSynchronized(int modifiers)
Modifier.isTransient(int modifiers)
Modifier.isVolatile(int modifiers)
Package Info
You can obtain information about the package from a Class object like this:
Class aClass = ... //obtain Class object. See prev. section
Package package = aClass.getPackage();
From the Package object you have access to information about the package like its name. You can also access
information specified for this package in the Manifest file of the JAR file this package is located in on the
classpath. For instance, you can specify package version numbers in the Manifest file. You can read more
about the Package class here: java.lang.Package
Superclass
From the Class object you can access the superclass of the class. Here is how:
Class superclass = aClass.getSuperclass();
The superclass class object is a Class object like any other, so you can continue doing class reflection on that
too.
Implemented Interfaces
It is possible to get a list of the interfaces implemented by a given class. Here is how:
Class aClass = ... //obtain Class object. See prev. section
Class[] interfaces = aClass.getInterfaces();
A class can implement many interfaces. Therefore an array of Class is returned. Interfaces are also represented
by Class objects in Java Reflection.
NOTE: Only the interfaces specifically declared implemented by a given class is returned. If a superclass of the
class implements an interface, but the class doesn't specifically state that it also implements that interface, that
interface will not be returned in the array. Even if the class in practice implements that interface, because the
superclass does.
To get a complete list of the interfaces implemented by a given class you will have to consult both the class and
its superclasses recursively.
Constructors
You can access the constructors of a class like this:
Constructor[] constructors = aClass.getConstructors();
Methods
You can access the methods of a class like this:
Method[] method = aClass.getMethods();
Fields
You can access the fields (member variables) of a class like this:
Field[] method = aClass.getFields();
Annotations
You can access the class annotations of a class like this:
Annotation[] annotations = aClass.getAnnotations();
The Constructor[] array will have one Constructor instance for each public constructor declared in the
class.
If you know the precise parameter types of the constructor you want to access, you can do so rather than obtain
the array all constructors. This example returns the public constructor of the given class which takes a String
as parameter:
Class aClass = ...//obtain class object
Constructor constructor =
aClass.getConstructor(new Class[]{String.class});
Constructor Parameters
You can read what parameters a given constructor takes like this:
Constructor constructor = ... // obtain constructor - see above
Class[] parameterTypes = constructor.getParameterTypes();
The Constructor.newInstance() method takes an optional amount of parameters, but you must supply
exactly one parameter per argument in the constructor you are invoking. In this case it was a constructor taking
a String, so one String must be supplied.
The Field[] array will have one Field instance for each public field declared in the class.
If you know the name of the field you want to access, you can access it like this:
Class aClass = MyObject.class
Field field = aClass.getField("someField");
The example above will return the Field instance corresponding to the field someField as declared in the
MyObject below:
public class MyObject{
public String someField = null;
}
If no field exists with the name given as parameter to the getField() method, a NoSuchFieldException is
thrown.
Field Name
Once you have obtained a Field instance, you can get its field name using the Field.getName() method, like
this:
Field field = ... //obtain field object
String fieldName = field.getName();
Field Type
You can determine the field type (String, int etc.) of a field using the Field.getType() method:
Field field = aClass.getField("someField");
Object fieldType = field.getType();
The objectInstance parameter passed to the get and set method should be an instance of the class that owns
the field. In the above example an instance of MyObject is used, because the someField is an instance member
of the MyObject class.
It the field is a static field (public static ...) pass null as parameter to the get and set methods, instead of the
objectInstance parameter passed above.
The Method[] array will have one Method instance for each public method declared in the class.
If you know the precise parameter types of the method you want to access, you can do so rather than obtain the
array all methods. This example returns the public method named "doSomething", in the given class which
takes a String as parameter:
Class aClass = ...//obtain class object
Method method =
aClass.getMethod("doSomething", new Class[]{String.class});
If no method matches the given method name and arguments, in this case String.class, a
NoSuchMethodException is thrown.
If the method you are trying to access takes no parameters, pass null as the parameter type array, like this:
Class aClass = ...//obtain class object
Method method =
aClass.getMethod("doSomething", null);
The null parameter is the object you want to invoke the method on. If the method is static you supply null
instead of an object instance. In this example, if doSomething(String.class) is not static, you need to supply
a valid MyObject instance instead of null;
The Method.invoke(Object target, Object ... parameters) method takes an optional amount of
parameters, but you must supply exactly one parameter per argument in the method you are invoking. In this
case it was a method taking a String, so one String must be supplied.
Setter
A setter method have its name start with "set", and takes 1 parameter.
Setters may or may not return a value. Some setters return void, some the value set, others the object the setter
were called on for use in method chaining. Therefore you should make no assumptions about the return type of
a setter.
Here is a code example that finds getter and setters of a class:
public static void printGettersSetters(Class aClass){
Method[] methods = aClass.getMethods();
for(Method method : methods){
if(isGetter(method)) System.out.println("getter: " + method);
if(isSetter(method)) System.out.println("setter: " + method);
}
}
public static boolean isGetter(Method method){
if(!method.getName().startsWith("get"))
return false;
if(method.getParameterTypes().length != 0)
return false;
if(void.class.equals(method.getReturnType()) return false;
return true;
}
public static boolean isSetter(Method method){
if(!method.getName().startsWith("set")) return false;
if(method.getParameterTypes().length != 1) return false;
return true;
}
This code example will print out the text "fieldValue = The Private Value", which is the value of the private
field privateString of the PrivateObject instance created at the beginning of the code sample.
Notice the use of the method PrivateObject.class.getDeclaredField("privateString"). It is this
method call that returns the private field. This method only returns fields declared in that particular class, not
fields declared in any superclasses.
Notice the line in bold too. By calling Field.setAcessible(true) you turn off the access checks for this
particular Field instance, for reflection only. Now you can access it even if it is private, protected or package
scope, even if the caller is not part of those scopes. You still can't access the field using normal code. The
compiler won't allow it.
This code example will print out the text "returnValue = The Private Value", which is the value returned by the
method getPrivateString() when invoked on the PrivateObject instance created at the beginning of the
code sample.
Notice the use of the method PrivateObject.class.getDeclaredMethod("privateString"). It is this
method call that returns the private method. This method only returns methods declared in that particular class,
not methods declared in any superclasses.
Notice the line in bold too. By calling Method.setAcessible(true) you turn off the access checks for this
particular Method instance, for reflection only. Now you can access it even if it is private, protected or package
scope, even if the caller is not part of those scopes. You still can't access the method using normal code. The
compiler won't allow it.
The @ in front of the interface marks it as an annotation. Once you have defined the annotation you can use it
in your code, as shown in the earlier examples.
The two directives in the annotation definition, @Retention(RetentionPolicy.RUNTIME) and
@Target(ElementType.TYPE), specifies how the annotation is to be used.
@Retention(RetentionPolicy.RUNTIME)
means that the annotation can only be used ontop of types (classes and
interfaces typically). You can also specify METHOD or FIELD, or you can leave the target out alltogether so the
annotation can be used for both classes, methods and fields.
Java annotations are explained in more detail in my Java Annotations tutorial.
Class Annotations
You can access the annotations of a class, method or field at runtime. Here is an example that accesses the class
annotations:
Class aClass = TheClass.class;
Annotation[] annotations = aClass.getAnnotations();
Method Annotations
Here is an example of a method with annotations:
public class TheClass {
@MyAnnotation(name="someName", value = "Hello World")
public void doSomething(){}
}
You can access method annotations like this:
Method method = ... //obtain method object
Annotation[] annotations = method.getDeclaredAnnotations();
for(Annotation annotation : annotations){
if(annotation instanceof MyAnnotation){
MyAnnotation myAnnotation = (MyAnnotation) annotation;
System.out.println("name: " + myAnnotation.name());
System.out.println("value: " + myAnnotation.value());
}
}
You can also access a specific method annotation like this:
Method method = ... // obtain method object
Annotation annotation = method.getAnnotation(MyAnnotation.class);
if(annotation instanceof MyAnnotation){
MyAnnotation myAnnotation = (MyAnnotation) annotation;
System.out.println("name: " + myAnnotation.name());
System.out.println("value: " + myAnnotation.value());
}
Parameter Annotations
It is possible to add annotations to method parameter declarations too. Here is how that looks:
public class TheClass {
public static void doSomethingElse(
You can access parameter annotations from the Method object like this:
Method method = ... //obtain method object
Annotation[][] parameterAnnotations = method.getParameterAnnotations();
Class[] parameterTypes = method.getParameterTypes();
int i=0;
for(Annotation[] annotations : parameterAnnotations){
Class parameterType = parameterTypes[i++];
for(Annotation annotation : annotations){
if(annotation instanceof MyAnnotation){
MyAnnotation myAnnotation = (MyAnnotation) annotation;
System.out.println("param: " + parameterType.getName());
System.out.println("name : " + myAnnotation.name());
System.out.println("value: " + myAnnotation.value());
}
}
}
Field Annotations
Here is an example of a field with annotations:
public class TheClass {
@MyAnnotation(name="someName", value = "Hello World")
public String myField = null;
}
You can access field annotations like this:
Field field = ... //obtain field object
Annotation[] annotations = field.getDeclaredAnnotations();
for(Annotation annotation : annotations){
if(annotation instanceof MyAnnotation){
MyAnnotation myAnnotation = (MyAnnotation) annotation;
System.out.println("name: " + myAnnotation.name());
System.out.println("value: " + myAnnotation.value());
}
}
You can also access a specific field annotation like this:
Field field = ... // obtain method object
Annotation annotation = field.getAnnotation(MyAnnotation.class);
if(annotation instanceof MyAnnotation){
MyAnnotation myAnnotation = (MyAnnotation) annotation;
System.out.println("name: " + myAnnotation.name());
System.out.println("value: " + myAnnotation.value());
}
When you write a class or interface you can specify that it should be paramerizable. This is the case with the
java.util.List interface. Rather than create a list of Object you can parameterize java.util.List to create
a list of say String.
When runtime inspecting a parameterizable type itself, like java.util.List, there is no way of knowing what
type is has been parameterized to. This makes sense since the type can be parameterized to all kinds of types in
the same application. But, when you inspect the method or field that declares the use of a parameterized type,
you can see at runtime what type the paramerizable type was parameterized to. In short:
You cannot see on a type itself what type it is parameterized to a runtime, but you can see it in fields and
methods where it is used and parameterized. Its concrete parameterizations in other words.
The following sections take a closer look at these situations.
In this class it is possible to obtain the generic return type of the getStringList() method. In other words, it is
possible to detect that getStringList() returns a List<String> and not just a List. Here is how:
Method method = MyClass.class.getMethod("getStringList", null);
Type returnType = method.getGenericReturnType();
if(returnType instanceof ParameterizedType){
ParameterizedType type = (ParameterizedType) returnType;
Type[] typeArguments = type.getActualTypeArguments();
for(Type typeArgument : typeArguments){
Class typeArgClass = (Class) typeArgument;
System.out.println("typeArgClass = " + typeArgClass);
}
}
This piece of code will print out the text "typeArgClass = java.lang.String". The Type[] array typeArguments
array will contain one item - a Class instance representing the class java.lang.String. Class implements the
Type interface.
You can access the generic parameter types of the method parameters like this:
method = Myclass.class.getMethod("setStringList", List.class);
Type[] genericParameterTypes = method.getGenericParameterTypes();
for(Type genericParameterType : genericParameterTypes){
if(genericParameterType instanceof ParameterizedType){
ParameterizedType aType = (ParameterizedType) genericParameterType;
Type[] parameterArgTypes = aType.getActualTypeArguments();
for(Type parameterArgType : parameterArgTypes){
Class parameterArgClass = (Class) parameterArgType;
System.out.println("parameterArgClass = " + parameterArgClass);
}
}
}
This code will print out the text "parameterArgType = java.lang.String". The Type[] array
parameterArgTypes array will contain one item - a Class instance representing the class java.lang.String.
Class implements the Type interface.
This code will print out the text "fieldArgClass = java.lang.String". The Type[] array fieldArgTypes array
will contain one item - a Class instance representing the class java.lang.String. Class implements the Type
interface.
java.lang.reflect.Array
Creating Arrays
Accessing Arrays
Obtaining the Class Object of an Array
Obtaining the Component Type of an Array
java.lang.reflect.Array
Working with arrays via Java Reflection is done using the java.lang.reflect.Array class. Do not confuse
this class with the java.util.Arrays class in the Java Collections suite, which contains utility methods for
sorting arrays, converting them to collections etc.
Creating Arrays
Creating arrays via Java Reflection is done using the java.lang.reflect.Array class. Here is an example showing
how to create an array:
int[] intArray = (int[]) Array.newInstance(int.class, 3);
This code sample creates an array of int. The first parameter int.class given to the Array.newInstance() method
tells what type each element in the array should be of. The second parameter states how many elements the
array should have space for.
Accessing Arrays
It is also possible to access the elements of an array using Java Reflection. This is done via the Array.get(...) and
Array.set(...) methods. Here is an example:
int[] intArray = (int[]) Array.newInstance(int.class, 3);
Array.set(intArray, 0, 123);
Array.set(intArray, 1, 456);
Array.set(intArray, 2, 789);
System.out.println("intArray[0] = " + Array.get(intArray, 0));
System.out.println("intArray[1] = " + Array.get(intArray, 1));
System.out.println("intArray[2] = " + Array.get(intArray, 2));
Doing this using Class.forName() is not quite straightforward. For instance, you can access the primitive int
array class object like this:
Class intArray = Class.forName("[I");
The JVM represents an int via the letter I. The [ on the left means it is the class of an int array I am interested
in. This works for all other primitives too.
For objects you need to use a slightly different notation:
Class stringArrayClass = Class.forName("[Ljava.lang.String;");
Notice the [L to the left of the class name, and the ; to the right. This means an array of objects with the given
type.
As a side note, you cannot obtain the class object of primitives using Class.forName(). Both of the examples
below result in a ClassNotFoundException:
Class intClass1 = Class.forName("I");
Class intClass2 = Class.forName("int");
I usually do something like this to obtain the class name for primitives as well as objects:
public Class getClass(String className){
if("int" .equals(className)) return int .class;
if("long".equals(className)) return long.class;
...
return Class.forName(className);
}
Once you have obtained the Class object of a type there is a simple way to obtain the Class of an array of that
type. The solution, or workaround as you might call it, is to create an empty array of the desired type and obtain
the class object from that empty array. It's a bit of a cheat, but it works. Here is how that looks:
Class theClass = getClass(theClassName);
Class stringArrayClass = Array.newInstance(theClass, 0).getClass();
This presents a single, uniform method to access the array class of arrays of any type. No fiddling with class
names etc.
To make sure that the Class object really is an array, you can call the Class.isArray() method to check:
Class stringArrayClass = Array.newInstance(String.class, 0).getClass();
System.out.println("is array: " + stringArrayClass.isArray());
This example will print out the text "java.lang.String" which is the component type of the String array.
Creating Proxies
You create dynamic proxies using the Proxy.newProxyInstance() method. The newProxyInstance()
methods takes 3 parameters:
1. The ClassLoader that is to "load" the dynamic proxy class.
2. An array of interfaces to implement.
3. An InvocationHandler to forward all methods calls on the proxy to.
Here is an example:
InvocationHandler handler = new MyInvocationHandler();
MyInterface proxy = (MyInterface) Proxy.newProxyInstance(
MyInterface.class.getClassLoader(),
new Class[] { MyInterface.class },
handler);
After running this code the proxy variable contains a dynamic implementation of the MyInterface interface. All
calls to the proxy will be forwarded to the handler implementation of the general InvocationHandler interface.
InvocationHandler's are covered i the next section.
InvocationHandler's
As mentioned earlier you must pass an InvocationHandler implementation to the
Proxy.newProxyInstance() method. All method calls to the dynamic proxy are forwarded to this
InvocationHandler implementation. Here is how the InvocationHandler interface looks:
public interface InvocationHandler{
Object invoke(Object proxy, Method method, Object[] args)
throws Throwable;
}
The proxy parameter passed to the invoke() method is the dynamic proxy object implementing the interface.
Most often you don't need this object.
The Method object passed into the invoke() method represents the method called on the interface the dynamic
proxy implements. From the Method object you can obtain the method name, parameter types, return type, etc.
See the text on Methods for more information.
The Object[] args array contains the parameter values passed to the proxy when the method in the interface
implemented was called. Note: Primitives (int, long etc) in the implemented interface are wrapped in their
object counterparts (Integer, Long etc.).
The Spring framework has a transaction proxy that can start and commit / rollback a transaction for you. How
this works is described in more detail in the text Advanced Connection and Transaction Demarcation and
Propagation , so I'll only describe it briefly. The call sequence becomes something along this:
web controller --> proxy.execute(...);
proxy --> connection.setAutoCommit(false);
proxy --> realAction.execute();
realAction does database work
proxy --> connection.commit();
The dependency injection container Butterfly Container has a powerful feature that allows you to inject the
whole container into beans produced by it. But, since you don't want a dependency on the container interface,
the container is capable of adapting itself to a custom factory interface of your design. You only need the
interface. No implementation. Thus the factory interface and your class could look something like this:
public interface IMyFactory {
Bean
bean1();
Person person();
...
}
public class MyAction{
protected IMyFactory myFactory= null;
public MyAction(IMyFactory factory){
this.myFactory = factory;
}
public void execute(){
Bean bean = this.myFactory.bean();
Person person = this.myFactory.person();
}
}
When the MyAction class calls methods on the IMyFactory instance injected into its constructor by the
container, the method calls are translated into calls to the IContainer.instance() method, which is the
method you use to obtain instances from the container. That way an object can use Butterfly Container as a
factory at runtime, rather than only to have dependencies injected into itself at creation time. And this without
having any dependencies on any Butterfly Container specific interfaces.
AOP-like Method Interception
The Spring framework makes it possible to intercept method calls to a given bean, provided that bean
implements some interface. The spring framework wraps the bean in a dynamic proxy. All calls to the bean are
then intercepted by the proxy. The proxy can decide to call other methods on other objects either before, instead
of, or after delegating the method call to the bean wrapped.
The ClassLoader
The ClassLoader Hierarchy
Class Loading
Dynamic Class Loading
Dynamic Class Reloading
Designing your Code for Class Reloading
ClassLoader Load / Reload Example
The ClassLoader
All classes in a Java application are loaded using some subclass of java.lang.ClassLoader. Loading classes
dynamically must therefore also be done using a java.lang.ClassLoader subclass.
When a class is loaded, all classes it references are loaded too. This class loading pattern happens recursively,
until all classes needed are loaded. This may not be all classes in the application. Unreferenced classes are not
loaded until the time they are referenced.
Class Loading
The steps a given class loader uses when loading classes are:
1. Check if the class was already loaded.
2. If not loaded, ask parent class loader to load the class.
3. If parent class loader cannot load class, attempt to load it in this class loader.
When you implement a class loader that is capable of reloading classes you will need to deviate a bit from this
sequence. The classes to reload should not be requested loaded by the parent class loader. More on that later.
Notice how the MyObject class is referenced in the code, as the type of the object variable. This causes the
MyObject class to be loaded by the same class loader that loaded the class this code is residing in.
If the myClassReloadingFactory object factory reloads the MyObject class using a different class loader than
the class the above code resides in, you cannot cast the instance of the reloaded MyObject class to the MyObject
type of the object variable. Since the two MyObject classes were loaded with different class loaders, the are
regarded as different classes, even if they have the same fully qualified class name. Trying to cast an object of
the one class to a reference of the other will result in a ClassCastException.
It is possible to work around this limitation but you will have to change your code in either of two ways:
1. Use an interface as the variable type, and just reload the implementing class.
2. Use a superclass as the variable type, and just reload a subclass.
Either of these two methods will work if the type of the variable, the interface or superclass, is not reloaded
when the implementing class or subclass is reloaded.
To make this work you will of course need to implement your class loader to let the interface or superclass be
loaded by its parent. When your class loader is asked to load the MyObject class, it will also be asked to load
the MyObjectInterface class, or the MyObjectSuperclass class, since these are referenced from within the
MyObject class. Your class loader must delegate the loading of those classes to the same class loader that
loaded the class containing the interface or superclass typed variables.
input.close();
byte[] classData = buffer.toByteArray();
return defineClass("reflection.MyObject",
classData, 0, classData.length);
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}
Here is the reflection.MyObject class that is loaded using the class loader. Notice how it both extends a
superclass and implements an interface. This is just for the sake of the example. In your own code you would
only have to one of the two - extend or implement.
public class MyObject extends MyObjectSuperClass implements AnInterface2{
//... body of class ... override superclass methods
//
or implement interface methods
}