Java Reflection

Basic

The following classes have useful static methods and do most of the work:

  1. Class
  2. java.lang.reflect.Field - A field can be a class, interface, or enum with an associated value.
  3. java.lang.reflect.Method
  4. java.lang.reflect.Constructor

Reflection Concerns

The following concerns should be kept in mind when accessing code via reflection:

  • Performance Overhead

Because reflection involves types that are dynamically resolved, certain Java virtual machine optimizations can not be performed. Consequently, reflective operations have slower performance than their non-reflective counterparts.

  • Security Restrictions

Reflection requires a runtime permission which may not be present when running under a security manager. This is in an important consideration for code which has to run in a restricted security context, such as in an Applet.

  • Exposure of Internals

Since reflection allows code to perform operations that would be illegal in non-reflective code, such as accessing private fields and methods, the use of reflection can result in unexpected side-effects, which may render code dysfunctional and may destroy portability. Reflective code breaks abstractions and therefore may change behavior with upgrades of the platform.

Class

For every type of object (reference or primitive type), JVM instantiates an immutable instance of java.lang.Class which provides methods to examine the runtime properties of the object including its members and type information.

Class cDoubleArray = Class.forName("[D");
The variable cDoubleArray will contain the Class corresponding to an array of primitive type double (i.e. the same as double[].class).

Class cStringArray = Class.forName("[[Ljava.lang.String;");
The cStringArray variable will contain the Class corresponding to a two-dimensional array of String (i.e. identical to String[][].class).

The value of Double.TYPE is identical to that of double.class.

Class c = Void.TYPE;
Void.TYPE is identical to void.class.

Class<?>[] c = Character.class.getClasses();
Returns all the public classes, interfaces, and enums that are members of the class including inherited members.

Class<?>[] c = Character.class.getDeclaredClasses();
Returns all of the classes interfaces, and enums that are explicitly declared in this class.

Field

Notice that some fields are reported even though they are not declared in the original code. This is because the compiler will generate some synthetic fields which are needed during runtime. To test whether a field is synthetic, invoke Field.isSynthetic().

The set of synthetic fields is compiler-dependent; however commonly used fields include:

this$0 for inner classes (i.e. nested classes that are not static member classes) to reference the outermost enclosing class
$VALUES used by enums to implement the implicitly defined static method values()

The names of synthetic class members are not specified and may not be the same in all compiler implementations or releases. These and other synthetic fields will be included in the array returned by Class.getDeclaredFields() but not identified by Class.getField() since synthetic members are not typically public.

Setting a field value

Given an instance of a class, it is possible to use reflection to set the values of fields in that class.
When using reflection to set or get a field, the compiler does not have an opportunity to perform boxing.

Method

A method can be invokes using reflection. Methods are inherited and in non-reflective code behaviors such as overloading, overriding, and hiding are enforced by the compiler. In contrast, reflective code makes it possible for method selection to be restricted to a specific class without considering its superclasses. Superclass methods may be accessed but it is possible to determine their declaring class; this is impossible to discover programmatically without reflection and is the source of many subtle bugs.

Generic Methods

Generics are implemented via type erasure which removes (erases) all information regarding generic types during compilation.

When a method is declared with a generic parameter type, the compiler will replace the generic type with its upper bound. Thus, when the code searches for the lower bound generic parameter we could get NoSuchMethodException.

Creating class instances

There are two reflective methods for creating instances of classes: java.lang.reflect.Constructor.newInstance() and Class.newInstance(). The former is preferred:

  • Class.newInstance() can only invoke the zero-argument constructor, while Constructor.newInstance() may invoke any constructor, regardless of the number of parameters.
  • Class.newInstance() throws any exception thrown by the constructor, regardless of whether it is checked or unchecked..
  • Class.newInstance() requires that the constructor be visible; Constructor.newInstance() may invoke private constructors under certain circumstances.

Enum constants

All enums extend java.lang.Enum
Useful methods for exploring enums: Class.isEnum(), Class.getEnumConstants(), and java.lang.reflect.Field.isEnumConstant().

There are lots of good examples in the tutorial.

Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License