Saturday, March 12, 2022

Java Reflection API Tutorial

As per Wikipedia; in computer science, reflection is the ability of a computer program to examine, introspect, and modify its own structure and behavior at runtime. Thus the Reflection API in Java provides the ability to examine or modify the runtime behavior of applications running in the Java virtual machine.

Using Reflection in Java you can inspect a class and get information about the fields, methods, constructors, implemented interfaces, super classes at run time, you can even invoke a method at run time. Using reflection you can also dynamically create and access Java arrays, examine the Enums, you can even access a private field and invoke a private method from another class!


Where is Reflection API used

Though you may not have a need to use reflection API in your application but you may be seeing its usage in many tools or applications you are using.

  1. The IDE like Eclipse giving you the list of methods in a class, auto completing the field or method name.
  2. Your persistence framework matching the fields in your objects with the fields in the DB table at runtime.
  3. Junit getting the information about the methods to be invoked.
  4. Spring framework getting the class information using the bean definition and also getting the setters and getters or constructor of the class. So you can say dependency injection in Spring depends heavily on reflection.

Reflection API in Java

Some of the main classes and interfaces which you will use while using reflection in Java are as follows–

  • Class- For every type of object, JVM instantiates an immutable instance of java.lang.Class (Note that Class itself is not part of Reflection API) which provides methods to examine the runtime properties of the object including its members and type information. Class also provides the ability to create new classes and objects. Most importantly, it is the entry point for all of the Reflection APIs. Refer Reflection in Java - Class to see examples of getting information about any class at run time.
  • Member- Reflection defines an interface java.lang.reflect.Member which is implemented by java.lang.reflect.Field, java.lang.reflect.Method, and java.lang.reflect.Constructor which can be used to get information about class members.
  • Field- Field class provides methods for accessing type information and setting and getting values of a field on a given object. To see examples of using Field class refer this post- Reflection in Java - Field.
  • Method- Method class provides methods for obtaining the type information for the parameters and return value. It may also be used to invoke methods on a given object. To see examples of using Method class refer this post- Reflection in Java - Method.
  • Constructor- Constructor class provides methods for obtaining the information about the constructors of the class. If you reflectively invoke a constructor it will create a new instance of an object for a given class. To see examples of using Constructor class refer this post- Reflection in Java - Constructor.
  • Array- The Array class provides static methods to dynamically create and access Java arrays. Reflection provides methods for accessing array types and array component types, creating new arrays, and retrieving and setting array component values. To see examples of using Array class refer this post- Reflection in Java - Array.

Java Reflection Example code

Here is an example of Java Reflection API to get an idea about how to use it. There is a class ClassA which has a constructor, private fields and getters and setters.

package org.prgm;

public class ClassA {
 private int i;
 private int j;
 // Constructor
 public ClassA(int i, int j){
  this.i = i;
  this.j = j;
 }
 public void setI(int i) {
  this.i = i;
 }
 public void setJ(int j) {
  this.j = j;
 }
 public int getI() {
  return i;
 }
 public int getJ() {
  return j;
 }
}

Using the following class you can get information about the constructor of the class, fields of the class and class methods.

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;

public class ReflectionDemo {

 public static void main(String[] args) {
  try {
   Class<?> c = Class.forName("org.prgm.ClassA");
   // Getting constructors of the class
   Constructor<?>[] constructors = c.getConstructors();
   System.out.println("Constructors - " + Arrays.toString(constructors));
   
   // Getting all methods (even inherited) of the class
   Method[] methods = c.getMethods();
   System.out.println("All Methods - " + Arrays.toString(methods));
   
   // Getting methods of the class
   methods = c.getDeclaredMethods();
   System.out.println("Class Methods - " + Arrays.toString(methods));
   
   // Getting fields of the class
   Field[] fields = c.getDeclaredFields();
   System.out.println("Fields - " + Arrays.toString(fields));
   
  } catch (ClassNotFoundException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }  
 }
}

Output

Constructors - [public org.prgm.ClassA(int,int)]

All Methods - [public int org.prgm.ClassA.getI(), public void org.prgm.ClassA.setI(int), public void org.prgm.ClassA.setJ(int), 
public int org.prgm.ClassA.getJ(), public final void java.lang.Object.wait() throws java.lang.InterruptedException, 
public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException, 
public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException, 
public boolean java.lang.Object.equals(java.lang.Object), public java.lang.String java.lang.Object.toString(), 
public native int java.lang.Object.hashCode(), public final native java.lang.Class java.lang.Object.getClass(), 
public final native void java.lang.Object.notify(), public final native void java.lang.Object.notifyAll()]

Class Methods - [public int org.prgm.ClassA.getI(), public void org.prgm.ClassA.setI(int), public void org.prgm.ClassA.setJ(int), 
public int org.prgm.ClassA.getJ()]

Fields - [private int org.prgm.ClassA.i, private int org.prgm.ClassA.j]

Drawbacks of Reflection in Java

Reflection provides a lot of power so it should not be used indiscriminately. If it is possible to perform an operation without using reflection, then it is preferable to avoid using it. Some of the drawbacks of Reflection are-

  1. Performance Overhead– Since reflection resolves types dynamically certain JVM optimizations can’t be performed. Thus the reflective operations have slower performance than their non-reflective counterparts. That means use of reflection in the sections of code which are called frequently in performance-sensitive applications should be avoided.
  2. Security Restrictions- Reflection requires a runtime permission which may not be present when running under a security manager. Thus the code which has to run in a restricted security context should avoid reflection.
  3. Against Object oriented principles- Since reflection allows code to perform operations that would be illegal in non-reflective code, such as accessing private fields and methods, the use of reflection can result in unexpected side-effects. Reflective code breaks abstractions and therefore may change behavior with upgrades of the platform.

Reference- https://docs.oracle.com/javase/tutorial/reflect/index.html

That's all for this topic Java Reflection API Tutorial. If you have any doubt or any suggestions to make please drop a comment. Thanks!

>>>Return to Java Advanced Tutorial Page


Related Topics

  1. Reflection in Java - Getting Method Information
  2. Reflection in Java - Getting Constructor Information
  3. Generating Getters And Setters Using Reflection in Java
  4. Java Object Cloning - clone() Method
  5. Serialization and Deserialization in Java

You may also like-

  1. instanceof Operator in Java
  2. BigDecimal in Java With Examples
  3. Try-With-Resources in Java With Examples
  4. Primitive Type Streams in Java Stream API
  5. Lambda Expressions in Java 8
  6. PermGen Space Removal in Java 8
  7. Generics in Java
  8. How HashMap Works Internally in Java