Skip to content

Reflection

When developing JDK 1.1, the developers were confronted with a weakness in Java that made it impossible to develop certain types of tools and libraries: the static structure of classes and objects. In order to create an object, to call one of its methods or to access one of its member variables, the code of the class had to be known at compile time. While this is not a problem for most common applications, it is inadequate for developing generic tools and highly configurable applications that are extensible with plug-ins. In particular, the development of the bean and serialization APIs was not possible with the language properties available in version 1.0.

Rather, what was needed was the ability to load and instantiate classes (also with parameterized constructors) without their name having to be known at compile time. Furthermore, static or instance-based methods should be called and member variables should be accessible even if their name is only known when the program is running.

So a mechanism was sought that made these runtime system capabilities, which are normally requested by the compiler, available to "normal" applications. With the Reflection API of JDK 1.1, a library interface was created that implements all of the abilities mentioned (and a few more) and makes it available to any application as an integral part of the Java class library. Extensions to the language core were not necessary.

Java is an object-oriented language, normally you should create an object and you can access the fields (field) or call the method (method) of the object using the operator (.)

Java Reflection presents a different approach. You can access a field of the object if you know the name of the field. Or you can call a method of the object if you know the name of the method, the parameter structure of the method and the value to be assigned

Java Reflecion allows you to evaluate and change the structure and behavior of an object at runtime of the program. At the same time, it allows you to access the member private (private member) anywhere in the application. That doesn't work with the traditional approach.

  1. Java can usually be called Java Introspection. The program can evaluate the structure of an object at runtime.
  2. With Java Reflection, the program can evaluate the structure of an object at runtime and change the structure and behavior of the object

The classes Object and Class

The Object class is the parent class of all other classes and ensures that some elementary methods such as equals, toString, clone or hashCode are available in all classes.

With the getClass method of the Object class, any object can deliver a suitable class object. For each class that the runtime system uses, a class object of the Class type is created during the loading process. The class Class provides methods for querying properties of the class and allows classes to be loaded dynamically and instances to be generated dynamically. It is also the key to the functionality of the Reflection API.

Let us first take a look at the dynamic loading and instantiation of classes using a simple example.

public abstract class Animal {
    public String getLocation() { return "Earth"; }
    public abstract int getNumberOfLegs() ;
}
public interface Say {
    public String say();
}
public class Cat extends Animal implements Say {
    public static final String SAY = "meo meo";
    public static final int NUMBER_OF_LEGS = 4;
    private String name;
    public int age;
    public Cat() {  }
    public Cat(String name) { this.name = name; this.age = 1; }
    public Cat(String name, int age) { this.name = name; this.age = age; }
    public String getName() { return this.name; }
    private void setName(String name) { this.name = name; }
    public int getAge() { return this.age; }
    public void setAge(int age) { this.age = age; }
    @Override
    public String say() { return SAY; }
    @Override
    public int getNumberOfLegs() { return NUMBER_OF_LEGS; }
}

Public methods

This is a simple example: Get the list from the public method of a class, including the inheritance method from the superclass and the interface.

public class ListMethod {
    // Protected method
    protected void info() { }
    public static void testMethod1() { }
    public void testMethod2() { }
    public static void main(String[] args) {
        // Get a list of public methods of this class
        // Include methods inherited from the parent class, or interface.
        Method[] methods = ListMethod.class.getMethods();
        for (Method method : methods) {
            System.out.println("Method " + method.getName());
        }
    }
}
// output:
Method main
Method testMethod1
Method testMethod2 
Method wait
Method equals
Method toString
Method hashCode
Method getClass
Method notify
Method notifyAll

getMethods returns an array of objects of the type Method that contains an element for each public method of the class. The getDeclaredMethods method can also be used to list the non-public methods. The Method class provides some methods for accessing the method object. The most important are:

String getName ()
int getModifiers ()
Class [] getParameterTypes ()
Object invoke (Object obj, Object [] args)

With getName the name of the method can be determined. getModifiers provides a bit-linked representation of the method attributes (static, private, etc.). The return value can be passed to the static methods of the Modifier class in order to determine which attributes the method has:

static boolean isAbstract (int mod)
static boolean isExplicit (int mod)
static boolean isFinal (int mod)
static boolean isInterface (int mod)
static boolean isNative (int mod)
static boolean isPrivate (int mod)
static boolean isProtected (int mod)
static boolean isPublic (int mod)
static boolean isStatic (int mod)
static boolean isStrict (int mod)
static boolean isSynchronized (int mod)
static boolean isTransient (int mod)
static boolean isVolatile (int mod)

getParameterTypes returns an array with objects of type Class which can be used to determine the number and types of formal arguments of the method. Each array element represents the class of the corresponding formal argument. If the array has the length 0, the method has no parameters. For example, if there are two elements with the types String and Double, the method has two parameters that are of the Type String and Double.

In order to be able to represent primitive types in this way, there is a static class object with the designation TYPE in the wrapper classes of the primitive types, which designates the associated primitive data type. An int argument is indicated, for example, by the fact that the return value of getParameterTypes contains an object of the type Integer.TYPE at the corresponding position. There are a total of nine such class objects, namely for the eight primitive types and for the "empty" return value void:

Class object type
Boolean.TYPE boolean
Character.TYPE char
Byte.TYPE byte
Short.TYPE short
Integer.TYPE int
Long.TYPE long
Float.TYPE float
Double.TYPE double
Void.TYPE void

The invoke method of the Method class is used to actually call the method represented by this method object. The first argument obj specifies the object on which the method is to be executed. Of course, it must belong to an object of the class on which getMethods was called. The second argument passes the current parameters to the method. Similar to getParameterTypes, an array is also specified here, the elements of which correspond to the corresponding current arguments. In the case of object parameters, an object of the appropriate type is simply placed at the desired location.

Class

Some important methods in Reflection relate to the class. Example of writing the basic information of the class such as the name of the class, package, modifier, etc.

public final class ShowClassInfo {
    public static void main(String[] args) {
        // Get Class object represent ShowClassInfo class.
        Class<ShowClassInfo> aClass = ShowClassInfo.class;
        // Print out class name, including the package name.
        System.out.println("Class Name= " + aClass.getName());
        // Print out simple class name (without package name).
        System.out.println("Simple Class Name= " + aClass.getSimpleName());
        Package pkg = aClass.getPackage(); // Package info
        System.out.println("Package Name = " + pkg.getName());
        int modifiers = aClass.getModifiers(); // Modifier
        boolean isPublic = Modifier.isPublic(modifiers);
        boolean isInterface = Modifier.isInterface(modifiers);
        boolean isAbstract = Modifier.isAbstract(modifiers);
        boolean isFinal = Modifier.isFinal(modifiers);
        System.out.println("Is Public? " + isPublic);  // true
        System.out.println("Is Final? " + isFinal); // true
        System.out.println("Is Interface? " + isInterface); // false
        System.out.println("Is Abstract? " + isAbstract); // false
    }
} 

Constructor

The example of getting a constructor with the certain parameter. And write down this constructor's information.

public class Example {
    public static void main(String[] args) throws NoSuchMethodException,... {
        // Get Class object represent Cat class.
        Class<Cat> aClass = Cat.class;
        // Get the Constructor object of the public constructor
        // that matches the specified parameterTypes
        Constructor<?> constructor = aClass.getConstructor(String.class,int.class);
        // Get parameter array of this constructor.
        Class<?>[] paramClasses = constructor.getParameterTypes();
        for (Class<?> paramClass : paramClasses) {
            System.out.println("Param: " + paramClass.getSimpleName());
        }
        // Initialize the object in the usual way
        Cat tom = new Cat("Tom", 3);
        System.out.println("Cat 1: " + tom.getName() + ", age =" + tom.getAge());
        // Using Java reflection to create object
        Cat tom2 = (Cat) constructor.newInstance("Tom", 2);
        System.out.println("Cat 2: " + tom.getName() + ", age =" + tom2.getAge());
    }
}

Field

The example of getting the field with a specific name.

public class FieldExample {
    public static void main(String[] args) throws NoSuchFieldException,... {
        // Get Class object represent Cat class
        Class<Cat> aClass = Cat.class;
        // Get Field object represent field 'NUMBER_OF_LEGS'.
        Field field = aClass.getField("NUMBER_OF_LEGS");
        Class<?> fieldType = field.getType();
        System.out.println("Field type: " + fieldType.getSimpleName());
        Field ageField = aClass.getField("age");
        Cat tom = new Cat("Tom", 5);
        // Returns the value of the field represented by this Field,
        // on the specified object.
        Integer age = (Integer) ageField.get(tom);
        System.out.println("Age = " + age);
        // Sets the field represented by this Field object on
        // the specified object argument to the specified new value.
        ageField.set(tom, 7);
        System.out.println("New Age = "+ tom.getAge());
    }
}

Methods

The example of getting a Method by a name and the previously determined parameter. Writing down the information about the method, list of parameters.

public class MethodExample {
    public static void main(String[] args) throws NoSuchMethodException,
        SecurityException, IllegalAccessException,
        IllegalArgumentException, InvocationTargetException {
        // Class object represent Cat class
        Class<Cat> aClass = Cat.class;
        // Method object represent getAge() method.
        Method getAgeMethod = aClass.getMethod("getAge");
        // return type of method.
        Class<?> returnType= getAgeMethod.getReturnType();
        System.out.println("Return type of getAge: "+ returnType.getSimpleName());
        Cat tom = new Cat("Tom", 7);
        // Call method 'getAge' way Reflect
        // This is equivalent to calling: tom.getAge()
        int age = (int) getAgeMethod.invoke(tom);
        System.out.println("Age = " + age);
        // Method object represent setAge(int) method of Cat class.
        Method setAgeMethod = aClass.getMethod("setAge", int.class);
         // Call method setAge(int) way Reflect
        // This is equivalent to calling: tom.setAge(5)
        setAgeMethod.invoke(tom, 5);
        System.out.println("New Age = " + tom.getAge());
    }
}

getter and setter method

The example below: the Public setter method and the Public getter method from the class listen.

public class GetSetExample {
    // Method is getter if names start with get, and no parameters.
    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;
    }
    // Method is setter if names start with set, and only one parameter.
    public static boolean isSetter(Method method) {
        if (!method.getName().startsWith("set")) { return false; }
        if (method.getParameterTypes().length != 1) { return false; }
        return true;
    }
    public static void main(String[] args) {
        // Class object represet Cat class
        Class<Cat> aClass = Cat.class;
        // public methods
        Method[] methods = aClass.getMethods();
        for (Method method : methods) {
            boolean isSetter = isSetter(method);
            boolean isGetter = isGetter(method);
            System.out.println("Method: " + method.getName());
            System.out.println(" - Is Setter? " + isSetter);
            System.out.println(" - Is Getter? " + isGetter);
        }
    }
}

Private fields

You cannot access the private method or field. The compiler of Java doesn't allow either. But it is possible with Java Reflection.

public class AccessPrivateFieldExample {
    public static void main(String[] args) throws IllegalArgumentException,... {
       // Class object represent Cat class
       Class<Cat> aClass = Cat.class;
       // Class.getField(String) get public field only.
       // Use Class.getDeclaredField(String):
       // Get the Field object of field declared in class.
       Field private_nameField = aClass.getDeclaredField("name");
       // Allows for access to private field.
       // Avoid IllegalAccessException
       private_nameField.setAccessible(true);
       Cat tom = new Cat("Tom");
       String fieldValue = (String) private_nameField.get(tom);
       System.out.println("Value field name = " + fieldValue);
       // Set new valud for 'name' field.
       private_nameField.set(tom, "Tom Cat");
       System.out.println("New name = " + tom.getName());
    }
}

and the next example is the access to the private method.

public class AccessPrivateMethodExample {
    public static void main(String[] args) throws NoSuchMethodException,... {
       // Class object represent Cat class.
       Class<Cat> aClass = Cat.class;
       // Class.getMethod(String) get public method only.
       // Use Class.getDeclaredMethod(String):
       // Get the Method object of method declared in class.        
       Method private_setNameMethod = aClass.getDeclaredMethod("setName", String.class);
       // Allows for access to private method.
       // Avoid IllegalAccessException        
       private_setNameMethod.setAccessible(true);
       Cat tom = new Cat("Tom");
       // Call private method
       private_setNameMethod.invoke(tom, "Tom Cat");
       System.out.println("New name = " + tom.getName());
    }
}
  • Exercise 1: implement a program that examines some given Java class, and report about these:
    • Method headers
    • Return value data types
    • Parameter data types