Everything in Java is an Object of a Class - including the classes themselves. Any class in Java is an object of java.lang.Class. It is defined its properties and has methods that allow you to work on these properties. This is a very powerful feature of the Java language. It allows your code to work on itself and produce amazing results.
This feature of Java language is covered under the Reflection API. Below, you can find few of the important modules of this Reflection API.
Class is the entry point for all reflection operations is java.lang.Class. There are several ways to get a Class depending on whether the code has access to an object, the name of class, a type, or an existing Class.
To get the class of an object - the class that is instantiated by the given object, you can use the method getClass()
Class c = object.getClass();
For any given class that is defined in the code, you can get the class object by accessing the field class. For example:
Class c = java.util.Date.class
If you have the name of the class in a String, you can get the corresponding Class object by using Class.forName() method. For example
String s = "java.util.Date";Class c = Class.forName(s);
The class Class is quite rich and provides several useful methods for working with the Class objects.
Some of the common methods are listed here.
|getSuperclass()||Returns the super class for the given class.|
|getClasses()||Returns all the public classes, interfaces, and enums that are members of the class including inherited members.|
|getDeclaredClasses()||Returns all of the classes interfaces, and enums that are explicitly declared in this class.|
|getDeclaringClass()||Returns the Class in which the class was declared. Anonymous Class Declarations will not have a declaring class but will have an enclosing class.|
|getEnclosingClass()||Returns the immediately enclosing class of the class.|
|getDeclaredField(String name)||Pick one field by name|
|getField(String name)||Pick one field by name|
|getDeclaredFields()||Get an array of Fields|
|getFields()||Get an array of Fields|
Any class has Member fields and member functions or methods. These are defined by the interface Member. Using the Java Reflection API, you can dynamically add Members to a given object. Such Members of the class are called Synthetic members. Members of a class have Modifiers and Annotations. The Member interface defines basic methods for interacting with a member of the class. It has 4 major implementations of this interface - Field, Executable, Method and Constructor
The fields in a class are represented by the class Field. You can identify the fields in a given class by using the method getFields().
Field fields = c.getFields()
You can also get a particular field by using its name
Field field = c.getField("fieldName")
Just like getField() and getFields(), you have two other methods getDeclaredField() and getDeclaredFields(). These refer fields that are declared within the given class and not inherited. The syntax is similar.
Field fields = c.getDeclaredFields()Field field = c.getDeclaredField("fieldName")
For a given Field object, you can identify the class where it is declared, by using the getDeclaringClass() method.
Field f = c.getDeclaredField("fileName");Class c = f.getDeclaringClass();
An Executable is a Member of the Class that can be executed. It could be a Method or a Constructor.
This defines any method in the class. You can get the list of methods in a class using getMethods() and getDeclaredMethods(). These are similar to the getFields() and getDeclaredFields(). You can also access individual methods by name and parameters. The Reflection API also allows you the invoke a given method on an object
Constructor is another type of Executable. It has most features similar to the Method. But instead of invoking the constructor (like the methods), you can trigger the constructor to get a newInstance()
Some of the common methods on the above classes are listed here.
|Member||getDeclaringClass()||Returns the Class object representing the class or interface that declares the member or constructor represented by this Member.|
|Member||getModifiers()||Returns the Java language modifiers for the member or constructor represented by this Member, as an integer.|
|Member||getName()||Returns the simple name of the underlying member or constructor represented by this Member.|
|Member||isSynthetic()||Returns true if this member was introduced by the compiler; returns false otherwise.|
|Field||getDeclaringClass()||Returns the Class in which the Field was declared.|
|Method||getDeclaringClass()||Returns the Class in which the method was declared.|
|Method||invoke(Object obj, Object... args)||Invokes the underlying method represented by this Method object, on the specified object with the specified parameters.|
|Constructor||getDeclaringClass()||Returns the Class in which the constructor was declared.|
|Constructor||newInstance(Object... initargs)||Uses the constructor represented by this Constructor object to create and initialize a new instance of the constructor's declaring class, with the specified initialization parameters.|
Any class or its members have associated Modifiers like static, public... These influence the behavior of the code. The Reflection API allows you to query and also modify these modifiers. getModifiers() returns an integer representing all the modifiers associated with the object. This number is composed of different flags related to each kind of modifiers. Instead of complicated binary calculations to extract these values, the Reflection API provides you with methods that help you with this task.
|Modifier.ABSTRACT||Modifier.isAbstract(int mod)||The int value representing the abstract modifier.|
|Modifier.FINAL||Modifier.isFinal(int mod)||The int value representing the final modifier.|
|Modifier.INTERFACE||Modifier.isInterface(int mod)||The int value representing the interface modifier.|
|Modifier.NATIVE||Modifier.isNative(int mod)||The int value representing the native modifier.|
|Modifier.PRIVATE||Modifier.isPrivate(int mod)||The int value representing the private modifier.|
|Modifier.PROTECTED||Modifier.isProtected(int mod)||The int value representing the protected modifier.|
|Modifier.PUBLIC||Modifier.isPublic(int mod)||The int value representing the public modifier.|
|Modifier.STATIC||Modifier.isStatic(int mod)||The int value representing the static modifier.|
|Modifier.STRICT||Modifier.isStrict(int mod)||The int value representing the strictfp modifier.|
|Modifier.SYNCHRONIZED||Modifier.isSynchronized(int mod)||The int value representing the synchronized modifier.|
|Modifier.TRANSIENT||Modifier.isTransient(int mod)||The int value representing the transient modifier.|
|Modifier.VOLATILE||Modifier.isVolatile(int mod)||The int value representing the volatile modifier.|
Additionally it provides a method toString(int mod), that returns a string describing the access modifier flags in the specified modifier.
On the first sight, Reflection may seem to be an esoteric feature that is rarely used. Why would anyone write code to know anything about class he defined! That may be right for small applications where one develops everything end to end. But in a massive real life application, there are a lot of scenarios where this is required. Frameworks like Spring and Hibernate are rooted in Reflection.
This is a top level introduction to the concepts of Java Reflection API. For more details, you can check out the Java Documentation.
If you want a detailed analysis, you can check out this book.