Java Reflection

Outline

What is reflection?

Reflection is the ability of a program to interrogate and manipulate its objects at runtime.

Example: BlueJ can instantiate a class without a main method, then let you invoke individual methods,

bluej screen capture

What can you do with reflection?

With the reflection API you can:

    * Determine the class of an object.
    * Get information about a class's modifiers, fields, methods, constructors, and superclasses.
    * Find out what constants and method declarations belong to an interface.
    * Create an instance of a class whose name is not known until runtime.
    * Get and set the value of an object's field, even if the field name is unknown to your program until runtime.
    * Invoke a method on an object, even if the method is not known until runtime.
    * Create a new array, whose size and component type are not known until runtime, and then modify the array's components.

How is this useful?

Extensibility Features
    Enables an application to use external, third-party "plug-in" classes.

Integrated Development Environments
    IDE's can benefit from making use of type information available in reflection to aid the developer in writing correct code, e.g. providing method signatures.

Debuggers and Test Tools
    Debuggers need to be able to examine private members of classes. Test harnesses can make use of reflection to systematically exercise the API of a class, to insure a high level of code coverage in a test suite.

Drawbacks

    Performance overhead
    Security
    Breaks encapsulation

Warning: Reflection is inherently insecure since there is no static type checking.  The examples here were performed by a professional driver on a closed track.

Simple Example


   import java.lang.reflect.*;
 
   public class DumpMethods
   {
      public static void main(String args[])
      {
         try {
            Class target = Class.forName(args[0]);
            Method methodList[] = target.getDeclaredMethods();
            for (int i = 0; i < methodList.length; i++)
            {
                System.out.println(methodList[i].toString());
            }   
         }
         catch (Throwable e) {
            System.err.println(e);
         }
      }
   }

  java DumpMethods java.util.Stack

yields the output:

  public java.lang.Object java.util.Stack.push(
java.lang.Object)
public synchronized
java.lang.Object java.util.Stack.pop()
public synchronized
java.lang.Object java.util.Stack.peek()
public boolean java.util.Stack.empty()
public synchronized
int java.util.Stack.search(java.lang.Object)

Could we use reflection in the Plugins Lab?


Demonstration of reflection to call constructors.
package Reflection;
import java.lang.reflect.Constructor;
import java.util.TreeSet;
import java.util.Arrays;
import java.util.Collection;
import java.util.AbstractSet;
public class CreateInstance
{
    /** Production code should catch all exceptions */
    @SuppressWarnings("unchecked")  // Warning - reflection is dangerous
    public static void main(String args[]) throws Throwable 
    {
        Class stringClass = java.lang.String.class;

        // creating an object with no arguments: String() 
        String myString = (String) stringClass.newInstance();
        myString = "Hello World"; 
        System.out.println("My String:" + myString);

        // creating an object with multiple arguments: String(char[] value, int offset, int count) 
        Constructor constructor = stringClass.getConstructor(new Class[] { char[].class, int.class, int.class });
        char[] word = {'M','y',' ','w','o','r','d'};
        myString = (String) constructor.newInstance(new Object[] { word, 3, 4 });  
        System.out.println("My String:" + myString);

        // creating an object with one argument that's an Object: TreeSet(Collection c) 
        Class setClass = java.util.TreeSet.class;
        constructor = setClass.getConstructor(new Class[] { Collection.class });
        String[] words = {"one","two","three"};
        Object[] arguments = new Object[1];
        arguments[0] = Arrays.asList(words);
        TreeSet mySet = (TreeSet) constructor.newInstance(arguments);
        System.out.println("My Set:" + mySet);
        
        // create an object for a class whose name we don't know at compile time
        Class someClass = Class.forName(args[0]);
        Object someThing = someClass.newInstance();
        // If the class is supposed to be derived from a base class (like java.util.TreeSet)
        AbstractSet aSet = (AbstractSet) someClass.newInstance();
        aSet.add("able");
        System.out.println("A Set:" + aSet);
    }
}

References:

  Horstmann, Ch 7.6
  Using Java Reflection
  The Reflection API Tutorial
  The Reflection API javadocs