Saturday, February 16, 2013

Reflection in Java

Reflection is one of the advanced features of Java through which you can perform operations which wouldn't be possible otherwise. Through this technique, you can discover information about a class at runtime. This is accomplished through a special kind of object called the Class object, which contains information about the class. 

The class, Class(yes, the name of the class is Class) supports the concept of reflection, along with other classes Field, Method, and Constructor from java.lang.reflect package. Using these APIs, class information of any anonymous objects can be completely determined at runtime (without any information at compile time). So the .class file which gets generated after compiling Java source code (or as a stream by downloading it from network), is opened and examined by the runtime environment. 

Reflection is used to support one of most advanced features of Java; Serialization.

API Details

class Class (from package java.lang) & classes from java.lang.reflect package

The instance of the class, Class represent classes and interfaces in a running Java application. An enum and array are a type of class and annotation is a kind of interface. 

Class API provides a static method to load the class (if it is not already loaded) and return a Class reference. It takes a fully qualified class name as the parameter( including package name).

         //Load and return the reference
         Class<?> c = Class.forName("package.ClassName");
       
        //only load the class
        Class.forName("package.ClassName");

If a class with name ClassName doesn't exist in the package then you will get runtime exception ClassNotFoundException.

So if you want to use type information at runtime, you must first get a reference to the appropriate Class object. But if you already have an object of the given class; then you can get the Class reference by calling getClass method (part of the Object root class).

          //Class<?> is preferred over plain Class; even though they are equivalent
          Class<?> c = obj.getClass();         

There is another alternative to above; by using class literal:
        Class<Integer> c = int.class;
        Class<House> h = House.class; 


Time to walk the talk


import java.lang.reflect.Method;

/**
 * Reflects ArrayList API of Java
 * 
 * @author Siddheshwar
 * 
 */
public class ReflectArrayList {

 public static void main(String[] args) throws Exception {
  Class<?> c = Class.forName("java.util.ArrayList");
  Object object = c.newInstance();

  // get handle of a method
  Method addMethod = c.getDeclaredMethod("add", Object.class);
  // add.setAccessible(true); //if add method is private
  addMethod.invoke(object, new String("sid"));
  addMethod.invoke(object, new String("rai"));

  Class<?> noparams[] = {};
  Method sizeMethod = c.getDeclaredMethod("size", noparams);
  System.out.println("size  of List: "
    + sizeMethod.invoke(object, noparams));

  Method toStringMethod = c.getMethod("toString", noparams);
  System.out.println("values of List : "
    + toStringMethod.invoke(object, null));  //null or noparams
  
 }
} 
 
Output
size  of List: 2
values of List : [sid, rai]

To avoid cluttering the code; I have thrown base Exception. But here is the complete list of Exceptions which will be thrown:
ClassNotFoundException, 
SecurityException, 
NoSuchMethodException, 
IllegalArgumentException, 
IllegalAccessException, 
InvocationTargetException &
InstantiationException

 Above code reflects ArrayList class; few important points:
  1. Class provides methods to return Method, Fields, and Constructors. 
  2. Method API provides a method to dynamically call a method at runtime (envoke spec)
  3. getMethods returns public members from the class/interface and its superclasses/super interfaces whereas getDeclaredMethods returns all methods declared by the class/interface.
  4. To call private method; set accessibility to true; as method.setAccessible(true)
References:

 

No comments:

Post a Comment