Java Reflection API
Java Reflection API provides us the ability to introspect and modify the runtime behavior of an application during runtime. Using Java Reflection we can inspect a class, interface, enum, get their structure, methods and fields information at runtime even though that class is not accessible at compile time. We can also use Reflection API to instantiate an object, call it’s methods, change field values.
The java.lang and java.lang.reflect packages provide necessary classes for the Reflection API.
The java.lang.Class is one of the most important class in Java programming. It is very useful in the sense that it provides several utility methods such as getClass(), forName() etc. which are used to find and load a class, we might have used them to load MySQL or Oracle drivers. See JDBC Tutorial for more details.
It also provides methods like Class.newInstance() which is the backbone of Reflection API and allow us to create an instance of a class without using new() operator. The class has no public constructor and its instance is created by JVM itself when a class is loaded. The object of class Class is also used to represent classes, enums, interfaces and annotations in a Java application during runtime.
The primitive types e.g. byte, short, int, long, float, double, char, and boolean are also represented by Class instances.
We can get the corresponding Class instance by using class literals e.g. int.class, double.class or boolean.class. It is also used to represent an instance of any Java array. Every array with the same type and same dimension share the same instance of the class Class.
Advantages :
- A Java application may make use of external, user-defined classes by creating instances of extensibility objects using their fully-qualified class names.
- Debugging, Testing tools and IDEs (NetBeans, Eclipse etc.) can use the property of reflection to introspect members of the classes.
Disadvantages:
- Reflective operations have slower performance compared to their non-reflective versions, and should be avoided in sections of code which are invoked frequently in performance-sensitive applications.
- Reflective codes expose internals as they break abstractions and therefore may change behavior with up-gradation of the platform.
Important methods of java.lang.Class
The special class Class
is the universal type for the meta information that describes objects within the JVM. Class loaders in the JVM return objects of type Class
. The three most important methods in this class are:
forName()
, which loads a class of a given name, using the current class loader. We must provide the fully-qualified class name here.getName()
, which returns the name of the class as aString
object, which is useful for identifying object references by their class names.newInstance()
, which invokes the null constructor on the class (if it exists) and returns us an object instance of that class of object.
To these three useful methods the Reflection API adds some additional methods to class Class
. These are as follows:
getConstructor()
,getConstructors()
,getDeclaredConstructor()
getMethod()
,getMethods()
,getDeclaredMethods()
getField()
,getFields()
,getDeclaredFields()
getSuperclass()
getInterfaces()
getDeclaredClasses()
In addition to these methods, the classes in the java.lang.reflect
package also have some useful methods for performing introspection and analysis.
NOTE: The getClass() method of java.lang.Object is an important method which returns the runtime class of an object and its return type is Class.
A Simple Example
The following example demonstrates how to get the instance of Class class in different ways. At the same time we would also like to determine if the specified Class object represents an interface type or class type by using isInterface() method of java.lang.Class. See the program below.
TestReflection.java
package techguru.examples;
class MyClass { } //a class
interface Intr { } //an interface
public class TestReflection {
// Technique 1: Using forName() method of Class class
static void method1() throws ClassNotFoundException {
System.out.println("From method1(): ");
Class c = Class.forName("techguru.examples.MyClass");
System.out.println(c.getName());
}
void display(Object obj) {
Class c = obj.getClass();
System.out.println(c.getName());
}
//Technique 2: Using getClass() method of Object class
static void method2() {
System.out.println("\nFrom method2(): ");
MyClass m = new MyClass();
TestReflection t = new TestReflection();
t.display(m);
}
//Technique 3: Using .class file extension and getName()
static void method3() {
System.out.println("\nFrom method3(): ");
Class c1 = MyClass.class;
System.out.println(c1.getName());
Class c2 = TestReflection.class;
System.out.println(c2.getName());
}
public static void main(String args[]) {
try {
method1(); //1
}
catch (ClassNotFoundException ex) {
ex.getMessage();
}
method2(); //2
method3(); //3
System.out.println("\nDetermining the interface or class object: ");
try {
Class c = Class.forName("techguru.examples.MyClass");
System.out.println(c.isInterface());
Class c2 = Class.forName("techguru.examples.Intr");
System.out.println(c2.isInterface());
}
catch (Exception e) {
System.out.println(e);
}
} //end of main()
} //end of class
Output:
Another Example
The following example demonstrates how to access the constructor, fields and methods of a class. Even our program will be able to access the private members of the class. We are using here Constructor, Field and Method classes of java.lang.reflect
package. At the beginning, the program might seem a little bit complex for the newbies. But, as one goes through the code and read the comments and checks the output, obviously it will be easier to comprehend. See the program below.
TestingReflection.java
package techguru.examples;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
class Sample {
//private field
private double pi;
//public constructor
public Sample() {
pi = 3.14;
}
//public method with no argument
public void showPI() {
System.out.println("PI: " + pi);
}
//public method with int as argument
public void powerOf2(int n) {
System.out.println("2^" + n + " is: " + Math.pow(2, n));
}
//private method
private void print() {
System.out.println("Bye from Reflection.");
}
}
public class TestingReflection {
public static void main(String[] args) throws Exception {
//loads the class and returns the reference of Class class
Class c = Class.forName("techguru.examples.Sample");
//prints the fully-qualified class name
System.out.println("Name of the class: " + c.getName());
//prints the constructor name
Constructor constructor = c.getConstructor();
System.out.println("Name of constructor: " + constructor.getName());
//creates new instance to access fields or methods
Object obj = c.newInstance();
Field field = c.getDeclaredField("pi");
field.setAccessible(true);
field.set(obj, 3.142);
//returns returns the method class instance
Method m = c.getDeclaredMethod("showPI", null);
//sets the accessibility of the method
m.setAccessible(true);
//used to invoke the method showPI()
m.invoke(obj, null);
//parameterized method powerOf2() called
m = c.getDeclaredMethod("powerOf2", new Class[]{int.class});
m.setAccessible(true);
m.invoke(obj,7);
//private method print() called
m = c.getDeclaredMethod("print", null);
m.setAccessible(true);
m.invoke(obj, null);
} //end of main()
} //end of class
Output:
Name of the class: techguru.examples.Sample
Name of constructor: techguru.examples.Sample
PI: 3.142
2^7 is: 128.0
Bye from Reflection.
SUMMARY
- Java Reflection API uses two packages namely java.lang and java.lang.reflect to introspect and modify the runtime behavior of a Java application during runtime.
- Reflection API provides us information about the class to which an object belongs and also the members of that class which can be accessed by using the object.
- Using Reflection API we can invoke members of a class at runtime regardless of the access specifier associated with them.