Reflection in Java

  • In Java, it is possible to inspect fields, classes, methods, annotations, interfaces, etc. at runtime.
  • There is no need to know how classes or methods are called, neither the parameters that are needed, all of that can be retrieved at runtime using Reflection.
  • It is also possible to instantiate new classes, to create new instances and to execute their methods, all of it using reflection.
  • Reflection is present in Java since the beginning of the times via its reflection API.
  • The class Class contains all the reflection related methods that can be applied to classes and objects like the ones that allow a programmer to retrieve the class name, to retrieve the public methods of a class, etc.
  • Other important classes are Method, Field and Type containing specific reflection methods.
  • Although reflection is very useful in many scenarios, it should not be used for everything. If some operation can be executed without using reflection, then we should not use it.
  • Here are some reasons:
    • The performance is affected by the use of reflection since all compilation optimizations cannot be applied: reflection is resolved at runtime and not at compile stages.
    • Security vulnerabilities have to be taken into consideration since the use of reflection may not be possible when running in secure contexts like Applets.
    • Another important disadvantage that is good to mention here is the maintenance of the code. If your code uses reflection heavily it is going to be more difficult to maintain. The classes and methods are not directly exposed in the code and may vary dynamically so it can get difficult to change the number of parameters that a method expects if the code that calls this method is invoked via reflection.
    • Tools that automatically refactor or analyze the code may have trouble when a lot of reflection is present.

Use cases

In general, reflection can be used to observe and modify the behavior of a program at runtime. Here is a list with the most common use cases:

  • IDEs can heavily make use of reflection in order to provide solutions for auto completion features, dynamic typing, hierarchy structures, etc. For example, IDEs like Eclipse or PHP Storm provide a mechanism to retrieve dynamically the arguments expected for a given method or a list of public methods starting by “get” for a given instance. All these are done using reflection.
  • Debuggers use reflection to inspect dynamically the code that is being executed.
  • Test tools like Junit or Mockito use reflection in order to invoke desired methods containing specific syntax or to mock specific classes, interfaces and methods.
  • Dependency injection frameworks use reflection to inject beans and properties at runtime and initialize all the context of an application.
  • Code analysis tools like PMD or Findbugs use reflection in order to analyze the code against the list of code violations that are currently configured.
  • External tools that make use of the code dynamically may use reflection as well.

Reflection components and mechanisms

  • Interface in Java is a contract with the applications that may use them. Interfaces contain a list of methods that are exposed and that have to be implemented by the subclasses implementing these interfaces. Interfaces cannot be instantiated. Since Java 8 they can contain default method implementations although this is not the common use.
  • Class is the implementation of a series of methods and the container of a series of properties. It can be instantiated.
  • Object is an instance of a given class.
  • Method is some code performing some actions. They have return types as outputs and input parameters.
  • Field is a property of a class.
  • Enums are elements containing a set of predefined constants.
  • Private element is an element that is only visible inside a class and cannot be accessed from outside. It can be a method, a field…
  • Static elements are elements that belong to the class and not to a specific instance. Static elements can be fields used across all instances of a given class, methods that can be invoked without need to instantiate the class, etc. This is very interesting while using reflection since it is different to invoke a static method than a non static one where you need an instance of a class to execute it.
  • Annotation is code Meta data informing about the code itself.
  • Collection is a group of elements, can be a List, a Map, a Queue, etc.
  • Array is an object containing a fixed number of values. Its length is fixed and is specified on creation.
  • Dynamic proxy is a class implementing a list of interfaces specified at runtime. They use the class java.lang.reflect.Proxy. We will see this more in detail in the next chapters.
  • Class loader is an object in charge of loading classes given the name of a class. In Java, every class provide methods to retrieve the class loader: Class.getClassLoader().
  • Generics were introduced in java update 5. They offer compile time safety by indicating what type or sub types a collection is going to use. For example using generics you can prevent that an application using a list containing strings would try to add a Double to the list in compile time.
[ad type=”banner”]

Classes

The class java.lang.Class contains several methods that allows to retrieve information about classes and objects (and other elements) at runtime.

In order to retrieve the class information from a single instance we can write (in this case, for the String class):

java code
Class<? extends String> stringGetClass = stringer.getClass();
  • Or directly from the class name without instantiation:
java code
Class<String> stringclass = String.class;
  • using the java.lang.Class.forName(String) method:
java code
Class.forName( "java.lang.String" )
  • From a class object we can retrieve all kind of information like declared methods, constructors, visible fields, annotations, types.
  • It is also possible to check properties for a given class like for example if a class is a primitive, or an instance:
java code
stringGetClass.isInstance( "dani" );

stringGetClass.isPrimitive();

 

  • It is also possible to create new instances of a given class using the method java.lang.Class.newInstance() passing the right arguments:
java code
String newInstanceStringClass = stringclass.newInstance();

  String otherInstance = (String)Class.forName( "java.lang.String" ).newInstance();

 

  • The java.lang.Class.newInstance() method can be used only when the class contains a public default constructor or a constructor without arguments, if this is not the case, this method cannot be used. In these cases where the java.lang.Class.newInstance() method cannot be used the solution is to retrieve a proper constructor at runtime and create an instance using this constructor with the arguments that it is expecting.

Interfaces

Interfaces are elements that cannot be instantiated and that contain the exposed methods that should be implemented by their subclasses. Related to reflection there is nothing special regarding interfaces.

  • Interfaces can be accessed like a class using their qualified name.
  • All methods available for classes are available for interfaces as well.
  • Here is an example of how to access interface class information at runtime:
java code
// can be accessed like a class
System.out.println( "interface name: " + InterfaceExample.class.getName() );

Enums

Enums are special java types that allow variables to be a set of constants. These constants are predefined in the enum declaration:

java code
enum ExampleEnum
{
ONE, TWO, THREE, FOUR
};

Java contains several enums specific methods:

  • java.lang.Class.isEnum(): Returns true if the element is of the type enum. False otherwise
  • java.lang.Class.getEnumConstants(): Gets all constants for the given element (which is an enum). In case the element is not an enum an exception is thrown.
  • java.lang.reflect.Field.isEnumConstant(): Returns true in case the field used is an enum constant. False otherwise. Only applicable to fields.

Primitive types

Examples of how to use reflection when we are working with primitive types:

  • It is possible to retrieve a class object from a primitive type as for any other non primitive type:
java code
Class<Integer> intClass = int.class;
  • But It is not possible to create new instances for primitive types using reflection:
java code
Integer intInstance = intClass.newInstance();
  • It is possible to check if a given class belongs to a primitive type or not using the method java.lang.Class.isPrimitive():
java code
System.out.println( "is primitive: " + intClass.isPrimitive() );

In this case an exception of the type java.lang.InstantiationException is going to be thrown.

Fields

  • Class fields can be handled in runtime using reflection. Classes offer several methods to access their fields at runtime. The most important ones are:
  • java.lang.Class.getDeclaredFields(): It returns an array with all declared fields for the class. It returns all private fields as well.
    • java.lang.Class.getFields(): It returns an array with all accessible fields for the class.
    • java.lang.Class.getField(String): It returns a field with the name passed as parameter. It throws an exception if the field does not exist or is not accessible.
    • java.lang.Class.getDeclaredFields(): It returns a field with the given name, if the field does not exist it throws an exception.
  • These methods return an array of elements (or a single one) of the type java.lang.reflect.Field. This class contains several interesting methods that can be used at runtime that allows to read the properties and the values of the specific field.

Methods

  • In order to retrieve all visible methods for a given class we can do the following:

 

java code
Class<String> stringclass = String.class;

Method[] methods = stringclass.getMethods();
  • Using the method java.lang.Class.getMethods() all visible or accessible methods for a given class are retrieved.
  • We can also retrieve an specific method using its name and the type of the arguments expecting to receive, as an example:
java code
Method methodIndexOf = stringclass.getMethod( "indexOf", String.class );
[ad type=”banner”]
  • For a given method (an instance of the type java.lang.reflect.Method), we can access all its properties.

Constructors

  • Constructors can be used via reflection as well. Like other class methods they can be retrieved in runtime and several properties can be analyzed and checked like the accessibility, the number of parameters, their types, etc.
  • In order to retrieve all visible constructors from a class, we can do something like:
java code
// get all visible constructors

Constructor<?>[] constructors = stringGetClass.getConstructors();

 

  • In the snippet above we are retrieving all visible constructors. If we want to get all the constructors, including the private ones, we can do something like:

 

java code
//all constructors

Constructor<?>[] declaredConstructors =   stringclass.getDeclaredConstructors();
[ad type=”banner”]
  • Constructors can also be used to create new instances. This may be very useful in order to access private or not visible constructors. This should be done only under very special circumstances and depending on the system where the application is running may not work because of security reasons

Getters and Setters

  • Getters and setters are not different to any other class method inside a class. The main difference is that they are a standard way to access private fields.
  • Here is a description of both:
  • Getters are used to retrieve the value of a private field inside a class. Its name starts with “get” and ends with the name of the property in camel case. They do not receive any parameter and their return type is the same than the property that they are returning. They are public.
  • Setters are used to modify the value of a private field inside a class. Its name starts with “set” and ends with the name of the property in camel case. They receive one parameters of the same type than the property that they are modifying and they do not return any value (void). They are public.

Static elements

  • Static classes, methods and fields behave completely different than instance ones.
  • The main reason is that they do not need to be instantiated or created before they are invoked. They can be used without previous instantiation.
  • This fact changes everything: static methods can be invoked without instantiating their container classes, static class fields are stateless (so thread safe), static elements are very useful in order to create singletons and factories… Summarizing, static elements are a very important mechanism in Java.
  • For example, for the next static inline class:
java code
public class StaticReflection
{
static class StaticExample

{
int counter;
}
...

In order to retrieve static inline classes we have the following options:

java code
// 1 access static class
System.out.println( "directly " + StaticExample.class.getName() );
//2 using for name directly throws an exception
Class<?> forname = Class.forName("com.danibuiza.javacodegeeks.reflection.StaticReflection.StaticExample" );
//3 using $ would work but is not that nice
Class<?> forname = Class.forName("com.danibuiza.javacodegeeks.reflection.StaticReflection$StaticExample" );

// 4 another way iterating through all classes declared inside this class
Class<?>[] classes = StaticReflection.class.getDeclaredClasses();
for( Class<?> class1 : classes )
{
System.out.println( "iterating through declared classes " + class1.getName() );
}
  • The main difference is that the class is contained inside another class; this has nothing to do with reflection but with the nature of inline classes.

Arrays

The class java.lang.reflect.Array offers several functionalities for handling arrays; it includes various static reflective methods:

java.lang.reflect.Array.newInstance(Class, int):

  • Creates a new instance of an array of the type passed as parameter with the length given in the second argument. Is similar to the method with the same name in the java.lang.Class class but this one contains parameters that allows the programmer to set the type of the array and its length.

java.lang.reflect.Array.set(Object, int, Object):

  • Sets an element (passed index) of the given array with the object passed as argument.

java.lang.reflect.Array.getLength(Object):

  • Returns the length of the array as int.

java.lang.reflect.Array.get(Object, int):

  • Retrieves the element of the array positioned in the pased index. Returns an object.

java.lang.reflect.Array.getInt(Object, int):

  • Similar method for the primitive type int. Returns an int. There are methods available for all primitive types.

Annotations

All annotations of a class, package, method, field, etc. can be retrieved using reflection. Annotations can be evaluated in runtime for each element and their values can be retrieved. The following snippet shows how to retrieve all annotations for a given class and how to print out their properties and values:

java code
Class<ReflectableClass> object = ReflectableClass.class;
// Retrieve all annotations from the class
Annotation[] annotations = object.getAnnotations();
for( Annotation annotation : annotations )
{
System.out.println( annotation );
}
[ad type=”banner”]

Generics

  • Generics were introduced in Java in the update 5 and since then are a very important feature that helps to maintain the code clean and more usable. Parameterized elements are not different than other elements in Java, so all the topics explained in this tutorial apply to these elements as well.
  • Java contains specific reflection mechanisms to handle generics as well.
    • It is possible to check at runtime if a specific element (class, method or field) is parameterized or not.
    • It is also possible to retrieve the parameters type using reflection as well.

Class Loaders

Elements in Java are loaded using class loaders. Class loaders can be implemented by implementing the abstract class

They provide functionalities to load classes using their names as parameters. A typical mechanism for loading classes is to find in the class path the file that belongs to the given name and open it converting it into a Java class. Every system (JVM) has a default one.

In order to retrieve the systems default class loader we can do the following:

java code
ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();

A programmer can also get the specific class loader used for loading a given class or instance. If nothing else is specified or configured, the default one is used. For example:

java code
ClassLoader classClassLoader = ReflectableClass.class.getClassLoader();

Using a class loader we can load classes at runtime passing as parameter the qualified name of a class, this name can be generated dynamically:

java code
Class<?> reflectableClassInstanceLoaded = systemClassLoader.loadClass( "com.danibuiza.javacodegeeks.reflection.ReflectableClass" );

Another possibility is to to this using Class.forName() method and specify the class loader that we want to use as parameter:

java code
Class<?> reflectableClassInstanceForName = Class.forName( "com.danibuiza.javacodegeeks.reflection.ReflectableClass", true, systemClassLoader );
  • Thus Reflection is a mechanism that allows programmers to analyze, modify and invoke code at runtime without previously knowing exactly what code they are executing.
  • Different use cases and applications can fit for using reflection like auto completion features in IDEs, unit testing processors, dependency injection or code analysis tools. It can also be used in normal applications for specific tasks but it should be avoided if possible since the performance and the security of the code will be affected. The maintenance effort will be increased in case the source code contains a lot of reflection.
  • Reflection in Java can be used in classes, methods, packages, fields, interfaces, annotations, etc. Using reflection it is possible to create new instance of any kind of object at runtime and to check its properties and values.
  • Since Java 8 the method getParameters() has been slightly modified and allows programmers to retrieve the actual names of method parameters

 

Categorized in: