Introduction -
Reflection is a powerful feature of a programming language that enables it to provide the ability to examine, inspect, “reflect on” or modify the structure of programs at runtime. Not all programming languages support it but the concepts and the principles related to it are usually the same in languages that support it.
Reflection in Java -
In Java, Reflection is a mechanism by which it exposes the features of a class during runtime thereby making it possible to enumerate and access the class’ fields, constructors, methods as objects. More specifically, Java provides object-based mirrors that reflect the Java object model and these objects can be used to access the object’s features at runtime using the runtime API constructs instead of compile-time language constructs.
Each object instance has a getClass() method, inherited from java.lang.Object, which returns an object with the runtime representation of that object's class; this object is an instance of the java.lang.Class, which in turn has methods that return the fields, methods, constructors, superclass, and other properties of that class. We can use these reflection objects to access fields, invoke methods, or instantiate instances, all without having compile-time dependencies on those features.
Reflection is a powerful technique and can enable applications to perform operations which would otherwise be impossible. But it should be used carefully as it is rightly said, “With great power comes great responsibility”. If it is possible to perform a task without reflection, then it is preferable to avoid using it because of some concerns related with reflection.
Performance concerns -
The Java virtual machine performs some internal optimizations for normal non-reflective code but as Reflection involves types that are dynamically resolved, these optimizations are not performed as a result of which the reflective operations are slower compared to their non-reflective counterparts. So reflection should be strictly avoided in sections of frequently accessed code in performance sensitive applications.
Exposure of Internals -
The use of reflection can cause unexpected side-effects, since it allows code to perform operations that are strictly speaking not legal in non-reflective code, such as accessing private fields and methods.
Demonstration -
Let’s see an example now where we will load a class “Employee” and access its fields and invoke its methods using reflection.Employee.java
The java class whose fields will be accessed and methods will be invoked using reflection.
package reflectiondemo;
public class Employee {
public int EmployeeAge;
public String EmployeeName;
public void printEmployeeName() {
System.out.println("Employee Name : " + EmployeeName);
}
public void printEmployeeAge() {
System.out.println("Employee Age : " + EmployeeAge);
}
public void setAndPrintEmployeeAge(int Age) {
EmployeeAge = Age;
System.out.println("Employee Age : " + EmployeeAge);
}
}
ReflectionDemo.java
This class will load the “Employee” class, create it’s new instance and access its fields and call its methods at runtime. The code is supplemented by self-explanatory comments.
package reflectiondemo;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class ReflectionDemo {
public static void main(String[] args) {
try {
//a Class array for invoking a no paramater method
Class noparams[] = {};
//a Class array for invoking a method with int parameter
Class[] paramInt = new Class[1];
paramInt[0] = Integer.TYPE;
//load the Employee class at runtime
Class cls = Class.forName("reflectiondemo.Employee");
//create a new instance of the Employee class
Object obj = cls.newInstance();
//get the field EmployeeAge
Field fieldEmployeeAge = cls.getField("EmployeeAge");
//set the EmployeeAge of the instance of Employee class
fieldEmployeeAge.set(obj, 25);
//get the field EmployeeName
Field fieldEmployeeName = cls.getField("EmployeeName");
//set the EmployeeName of the instance of Employee class
fieldEmployeeName.set(obj, "John");
//call the printEmployeeName method
Method method = cls.getDeclaredMethod("printEmployeeName",noparams);
method.invoke(obj, null);
//call the printEmployeeAge method
method = cls.getDeclaredMethod("printEmployeeAge", noparams);
method.invoke(obj, null);
//call the setAndPrintEmployeeAge method, pass a int param
method = cls.getDeclaredMethod("setAndPrintEmployeeAge", paramInt);
method.invoke(obj, 35);
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
Output -
Employee Name : John
Employee Age : 25
Employee Age : 35
Conclusion -
To conclude, we have seen an overview of Reflection in Java, a related example demonstrating the use of Reflection API and some concerns related to the usage of reflection which point that it should be used carefully to avoid performance overhead and some related side-effects.