Reflection is a way to inspect the internals of a class at runtime. It's a powerful feature but has to be handled with care. It in some sense breaks the notion of Object oriented concept. When we make a variable or method private we assume that the world is not able to see it. With reflection that's not true. With reflection one can inspect the internal details of a class and can even call methods and set attributes.
Let's see this with an example. Let's say we have a class that we want to reflect
Let's see this with an example. Let's say we have a class that we want to reflect
public class ClassToReflect {
//No arg constructor
public ClassToReflect(){
System.out.println("No argument Constructor");
}
//Constructor with argument
public ClassToReflect(String arg){
privateVariable = arg;
System.out.println("Argument Constructor woth argument " + arg);
}
private String privateVariable;
public String publicVariable;
private void privateMethod(){
System.out.println("Inside Private Method");
}
public void publicMethod(){
System.out.println("Inside Public Method");
}
}
Now let's see how we can do a reflection on the above class. We will do the following in the code:
- Get the class instance
- Get the constructor and make and object/instance of the reflected class
- Access public and private variables
- Access public and private methods and invoke them.
//Getting the class
Class classToReflect = ClassToReflect.class;
System.out.println("Class to Reflect: " +
classToReflect.getSimpleName());
//Get the constructor
Constructor[] constructors =
classToReflect.getConstructors();
for(Constructor c: constructors){
System.out.println("Constructor: " + c.getName());
Parameter[] parameters = c.getParameters();
for(Parameter p: parameters){
System.out.println("Parameter: " + p.getName());
}
}
//Creating an object using argument constructor
ClassToReflect objectOfClass = null;
try {
Constructor constructorWithArgument =
classToReflect.getConstructor(String.class);
objectOfClass =
(ClassToReflect)constructorWithArgument.newInstance("Argument");
} catch (Exception e) {
//I am handling generic exception. However you might want to
//handle fine grained exception
e.printStackTrace();
}
//Get the variables.
//Modifiers tell about the type of variable. In our case the modifier are
//PUBLIC -1
//PRIVATE - 2
//For details about modifiers see javadoc of Modifier. Modifier values
//represent bit positions so that has to be decoded from that perspective.
//Calling getFields method will only return the public fields
Field[] fields = classToReflect.getDeclaredFields();
//Print fields list
for(Field f: fields){
System.out.println("Field: " + f.getName() +
", Type: " + f.getType() +
", Modifier: " + f.getModifiers() );
}
//For private variable we can get the value of the variable by making an
//object
try {
//Get the private field of object we constructed above
Field privateVariableField = classToReflect.getDeclaredField("privateVariable");
//To access the value, set accessible needs to be set true. Not a good
//idea as this breaks the object oriented concepts
//Try commenting this and you will see an exception.
privateVariableField.setAccessible(true);
System.out.println("Value: " + privateVariableField.get(objectOfClass));
} catch (Exception e) {
System.out.println("Exception: " + e.getMessage());
}
//For methods. We will see only public method. getMethods will return
//all the methods from super class also
Method[] methods = classToReflect.getDeclaredMethods();
//Print methods list
for(Method m: methods){
System.out.println("Method: " + m.getName() +
", Return Type: " + m.getReturnType() +
", Modifier: " + m.getModifiers());
Parameter[] parameters = m.getParameters();
for(Parameter p: parameters){
System.out.println("Parameter Type: " + p.getType());
}
}
//Invoking public method
try {
Method publicMethodToInvoke = classToReflect.getDeclaredMethod("publicMethod", null);
publicMethodToInvoke.invoke(objectOfClass,null);
} catch (Exception e) {
e.printStackTrace();
}
//Invoking private method
try {
Method privateMethodToInvoke = classToReflect.getDeclaredMethod("privateMethod", null);
//Need to set the accessibility as true
//Not a good idea
privateMethodToInvoke.setAccessible(true);
privateMethodToInvoke.invoke(objectOfClass,null);
} catch (Exception e) {
e.printStackTrace();
}
On running the above you will see the out put as follows:
Class to Reflect: ClassToReflect
Constructor: com.lalit.javaExamples.reflection.ClassToReflect
Constructor: com.lalit.javaExamples.reflection.ClassToReflect
Parameter: arg0
Argument Constructor woth argument Argument
Field: privateVariable, Type: class java.lang.String, Modifier: 2
Field: publicVariable, Type: class java.lang.String, Modifier: 1
Value: Argument
Method: publicMethod, Return Type: void, Modifier: 1
Method: privateMethod, Return Type: void, Modifier: 2
Inside Public Method
Inside Private Method
There are some downside to the reflection:
- Reflection exposes the internals of a class. For example we can invoke private methods. This breaks the contract of object orientation and may conflict with security managers also
- Reflection has performance penalty as lot of things has to be resolved at runtime.This is primarily because the compile time optimizations cannot be applied
No comments:
Post a Comment