What is Reflection?
This is used to examine the Classes, Methods, Fields, Interfaces at runtime and also possible to change the behavior of the class too.
For example:
What all methods present in the class.
What all fields present in the class.
What is the return type of the method.
What is the Modifier of the class.
What all interfacess class has implemented
Change the value of the public and private fields of the Class etc..
How to do Reflection of Classes?
To reflect the class, we first need to get an Object of Class.
(So, lets first understand, Class then we will come back to how to reflect the class)
What is this class Class?
Instance of the class Class represents classes during runtime.
JVM creates one Class object for each and every class which is loaded during run time.
This Class object, has meta data information about the particular class like its method, fields, constructor etc.
How to get the particular class Class object?
There are 3 ways:
Using forName()
method
//Assume that we have one class called Bird
class Bird {}
//get the object of Class for getting the metadata
// information of Bird class.
Class birdClass = Class.forName("Bird");
Using .class
//Assume that we have one class called Bird
class Bird {}
//get the object of Class for getting the metadata
//information of Bird class.
Class birdClass = Bird.class;
Using getClass()
method
//Assume that we have one class called Bird
class Bird {}
Bird birdObj = new Bird();
//get the object of Class for getting the metadata
//information of Bird class.
Class birdClass = birdObj.getClass();
Reflection of Classes
Now lets get back to, how to do Reflection of Classes
package learn.Reflection;
public class Eagle {
public String bread;
private boolean canSwim;
public void fly(){
System.out.println("Fly");
}
public void eat(){
System.out.println("eat");
}
}
public class Main {
public static void main(String[] args) {
Class eagleClass = Eagle.class;
System.out.println(eagleClass.getName());
//Eagle class modifier is public -> public class Eagle
System.out.println(Modifier.toString(eagleClass.getModifiers()));
}
}
/*
----------------Output ---------------
learn.Reflection.Eagle
public
*/
Methods Available in Class Object, all are get, no set methods.
The package "java.lang.reflect" provides classes that can be used to access and manipulate the value like fields, methods, constructor etc.
These classes are generally returned by above listed get Methods only.
Reflection of Methods
Consider the following class
package learn.Reflection;
public class Eagle {
public String bread;
private boolean canSwim;
public void fly(){
System.out.println("Fly");
}
private void eat(){
System.out.println("eat");
}
}
getMethods
getMethods will return all public methods.
package learn.Reflection;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
public class Main {
public static void main(String[] args) {
Class eagleClass = Eagle.class;
Method[] methods = eagleClass.getMethods();
for (Method method : methods) {
System.out.println("Method name: " + method.getName());
System.out.println("Return Type: " + method.getReturnType());
System.out.println("Class name: " + method.getDeclaringClass());
System.out.println("********");
}
}
}
Output -
Method name: fly
Return Type: void
Class name: class learn.Reflection.Eagle
********
Method name: wait
Return Type: void
Class name: class java.lang.Object
********
Method name: wait
Return Type: void
Class name: class java.lang.Object
********
Method name: wait
Return Type: void
Class name: class java.lang.Object
********
Method name: equals
Return Type: boolean
Class name: class java.lang.Object
********
Method name: toString
Return Type: class java.lang.String
Class name: class java.lang.Object
********
Method name: hashCode
Return Type: int
Class name: class java.lang.Object
********
Method name: getClass
Return Type: class java.lang.Class
Class name: class java.lang.Object
********
Method name: notify
Return Type: void
Class name: class java.lang.Object
********
Method name: notifyAll
Return Type: void
Class name: class java.lang.Object
********
getDeclaredMethods
All public and private methods it will return within Eagle class only.
public class Main {
public static void main(String[] args) {
Class eagleClass = Eagle.class;
Method[] methods = eagleClass.getDeclaredMethods();
for (Method method : methods) {
System.out.println("Method name: " + method.getName());
System.out.println("Return Type: " + method.getReturnType());
System.out.println("Class name: " + method.getDeclaringClass());
System.out.println("********");
}
}
}
// Output ----------------
Method name: fly
Return Type: void
Class name: class learn.Reflection.Eagle
********
Method name: eat
Return Type: void
Class name: class learn.Reflection.Eagle
********
Invoking Method using Reflection
public class Eagle {
Eagle(){ }
public void fly(int intParam, boolean boolParam, String strParam){
System.out.println("fly intParam:"+intParam + "boolParam: "+boolParam + "strParam: "+strParam);
}
}
package learn.Reflection;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class Main {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, InstantiationException {
Class eagleClass = Class.forName("learn.Reflection.Eagle");
// New instance creation is depreciated
// Object eagleObject = eagleClass.newInstance();
Object eagleObject = eagleClass.newInstance();
Method flyMethod = eagleClass.getMethod("fly", int.class, boolean.class,String.class);
flyMethod.invoke(eagleObject, 1, true, "hello");
}
}
//Output -------------
fly intParam:1boolParam: truestrParam: hello
Reflection of Fields
package learn.Reflection;
public class Eagle {
public String bread;
private boolean canSwim;
public void fly(){
System.out.println("Fly");
}
private void eat(){
System.out.println("eat");
}
}
Reflection - All public fields
public class Main {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, InstantiationException {
Class eagleClass = Class.forName("learn.Reflection.Eagle");
//Get public fields with this
Field[] fields = eagleClass.getFields();
for (Field field: fields){
System.out.println("FieldName: "+field.getName());
System.out.println("Type: "+field.getType());
System.out.println("Modifier: "+ Modifier.toString(field.getModifiers()));
System.out.println("********");
}
}
}
//Output -----------
FieldName: bread
Type: class java.lang.String
Modifier: public
********
Reflection - All fields
public class Main {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, InstantiationException {
Class eagleClass = Class.forName("learn.Reflection.Eagle");
//Get public fields with this
Field[] fields = eagleClass.getDeclaredFields();
for (Field field: fields){
System.out.println("FieldName: "+field.getName());
System.out.println("Type: "+field.getType());
System.out.println("Modifier: "+ Modifier.toString(field.getModifiers()));
System.out.println("********");
}
}
}
//output-----
FieldName: bread
Type: class java.lang.String
Modifier: public
********
FieldName: canSwim
Type: boolean
Modifier: private
********
Setting the value of Public Field
public class Main {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, InstantiationException, NoSuchFieldException {
Class eagleClass = Class.forName("learn.Reflection.Eagle");
Eagle eagleObj = new Eagle();
//Get both public and private fields with this
Field field = eagleClass.getDeclaredField("bread");
field.set(eagleObj,"eagle brown breed");
System.out.println(eagleObj.bread);
}
}
Incorrect way: Setting the value of private field
public class Main {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, InstantiationException, NoSuchFieldException {
Class eagleClass = Class.forName("learn.Reflection.Eagle");
Eagle eagleObj = new Eagle();
//Get both public and private fields with this
Field field = eagleClass.getDeclaredField("canSwim");
field.set(eagleObj, true);
if(field.getBoolean(eagleObj)){
System.out.println("value is set to true");
}
}
}
/*
Output -
Exception in thread "main" java.lang.IllegalAccessException: class learn.Reflection.Main cannot access a member of class learn.Reflection.Eagle with modifiers "private"
at java.base/jdk.internal.reflect.Reflection.newIllegalAccessException(Reflection.java:392)
at java.base/java.lang.reflect.AccessibleObject.checkAccess(AccessibleObject.java:674)
at java.base/java.lang.reflect.Field.checkAccess(Field.java:1102)
at java.base/java.lang.reflect.Field.set(Field.java:797)
at learn.Reflection.Main.main(Main.java:18)
*/
Setting the value of private field
public class Main {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, InstantiationException, NoSuchFieldException {
Class eagleClass = Class.forName("learn.Reflection.Eagle");
Eagle eagleObj = new Eagle();
//Get both public and private fields with this
Field field = eagleClass.getDeclaredField("canSwim");
field.setAccessible(true);
field.set(eagleObj, true);
if(field.getBoolean(eagleObj)){
System.out.println("value is set to true");
}
}
}
/*
Output -
value is set to true
*/
Reflection of Constructor
We can also instantiate a class that has a private constructor. The reflection property breaks the singleton property. To attain the singleton property, we need to add a check in the constructor to see if the object has been created earlier or not (null check).
public class Eagle {
private Eagle(){
System.out.println("Private constructor");
}
public void fly(){
System.out.println("fly");
}
}
public class Main {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, InstantiationException, NoSuchFieldException {
Class eagleClass = Eagle.class;
Constructor[] eagleConstructorList = eagleClass.getDeclaredConstructors();
for (Constructor eagleConstructor: eagleConstructorList){
System.out.println("Modifier: "+ Modifier.toString(eagleConstructor.getModifiers()));
eagleConstructor.setAccessible(true);
Eagle eagleObject = (Eagle) eagleConstructor.newInstance();
eagleObject.fly();
}
}
}