Reflection API

Java Reflection API is part of the java.lang.reflect and java.lang packages. It allows inspection and manipulation of classes, interfaces, constructors, methods, and fields at runtime—even if they are private. This capability is extremely useful for frameworks, development tools, and advanced operations such as serialization, dependency injection, and testing.

What is the Reflection API?

The Reflection API in Java allows a program to:

  • Examine or modify the runtime behavior of applications.
  • Access private fields and methods of a class.
  • Instantiate objects dynamically.
  • Invoke methods or access fields dynamically.
  • Analyze class information at runtime (e.g., methods, fields, annotations).

Core classes in the Java Reflection API

1.Class<T> (Package: java.lang)

 Purpose

The Class<T> class is the central class in the reflection API. It represents classes and interfaces in a running Java application. Every Java object belongs to a class, and calling getClass() on an object returns its Class object.

Key Features

  • Load classes dynamically (Class.forName()).
  • Access constructors, methods, fields, and annotations.
  • Create instances using constructors.
  • Determine superclass, interfaces, and modifiers.

Common Use Cases

  • Dynamic class loading.
  • Frameworks like Spring and Hibernate for bean instantiation.
  • Object serialization/deserialization.
 2. Field (Package: java.lang.reflect)

Purpose

The Field class provides information about, and dynamic access to, a single field of a class or an interface.

Key Features

  • Get the name, type, and modifiers of a field.
  • Read and write field values at runtime—even if private.
  • Bypass Java access controls using setAccessible(true).

Common Use Cases

  • Serialization libraries to inspect and read fields.
  • Frameworks needing to inject values into object fields.
3. Method (Package: java.lang.reflect)

Purpose

The Method class allows access to and invocation of class or interface methods at runtime.

Key Features

  • Get method name, return type, parameter types, and modifiers.
  • Invoke methods dynamically with arguments.
  • Call private methods using setAccessible(true).

Common Use Cases

  • Implementing callbacks and event systems.
  • Dynamic behavior implementation (like JavaBeans or scripting engines).
  • Test frameworks invoking private methods.
4. Constructor<T> (Package: java.lang.reflect)

Purpose

The Constructor<T> class provides information about, and access to, a single constructor of a class.

 Key Features

  • Get constructor’s name and parameter types.
  • Create new instances using newInstance().
  • Access private constructors using setAccessible(true).

Common Use Cases

  • Dependency injection containers (like Spring).
  • Object creation in serialization frameworks.
  • Reflective instantiation in dynamic modules or plug-ins.
5. Modifier (Package: java.lang.reflect)

Purpose

The Modifier class provides static methods to decode class and member access modifiers like public, private, static, etc.

Key Features

  • Identify if a field or method is public, private, abstract, etc.
  • Interpret integer modifiers returned by getModifiers().

Common Use Cases

  • Generating documentation or GUI elements based on member visibility.
  • Code analysis and debugging tools.
6. Array (Package: java.lang.reflect)

Purpose

The Array class allows dynamic creation and access to Java arrays regardless of their type.

Key Features

  • Create new arrays at runtime.
  • Get or set elements dynamically.
  • Get array length programmatically.

Common Use Cases

  • Frameworks needing to manipulate arrays without knowing their types at compile-time.
  • Generic algorithms or utilities working with various array types.
7. AnnotatedElement (Interface, Package: java.lang.reflect)

 Purpose

This interface is implemented by all elements that can have annotations: Class, Method, Field, Constructor, etc.

Key Features

  • Retrieve annotations at runtime.
  • Determine if an element has a specific annotation.

Common Use Cases

  • Annotation-driven configuration (e.g., in Spring Boot, JPA).
  • Custom processing tools or validators.

Methods in Class<T> (Package: java.lang)

Example Program: Using Reflection to Access Class Information

import java.lang.reflect.*;

class BankAccount {
    private String accountHolder = "LotusJavaPrince";
    private double balance = 10000.0;

    public BankAccount() {}

    public void deposit(double amount) {
        balance += amount;
    }

    private void showSecretCode() {
        System.out.println("Secret Code: 789XYZ");
    }
}

public class ReflectionExample {
    public static void main(String[] args) throws Exception {
        // Load class dynamically
        Class<?> clazz = Class.forName("BankAccount");

        // Create instance
        Object obj = clazz.getDeclaredConstructor().newInstance();

        // Print class name
        System.out.println("Class: " + clazz.getName());

        // Get all fields
        Field[] fields = clazz.getDeclaredFields();
        System.out.println("\nFields:");
        for (Field field : fields) {
            field.setAccessible(true);  // bypass private modifier
            System.out.println(field.getName() + " = " + field.get(obj));
        }

        // Get all methods
        Method[] methods = clazz.getDeclaredMethods();
        System.out.println("\nMethods:");
        for (Method method : methods) {
            System.out.println(method.getName());

            // Call private method
            if (method.getName().equals("showSecretCode")) {
                method.setAccessible(true);
                method.invoke(obj);
            }
        }

        // Get and invoke a public method
        Method depositMethod = clazz.getMethod("deposit", double.class);
        depositMethod.invoke(obj, 5000.0);
        System.out.println("\nInvoked deposit method.");

        // Print updated balance
        for (Field field : fields) {
            if (field.getName().equals("balance")) {
                System.out.println("Updated Balance = " + field.get(obj));
            }
        }
    }
}

Use Cases in Real Applications

  • Spring Framework: Inject dependencies into classes dynamically.
  • JUnit: Access private test methods and variables.
  • ORM tools (Hibernate): Map Java classes to database tables.
  • IDE tools: Provide code completion, class navigation, etc.

The Reflection API in Java offers a powerful way to inspect and interact with classes at runtime. While it is invaluable in certain contexts, developers should use it judiciously due to performance and security considerations. Understanding how to use it properly opens the door to building dynamic and flexible applications.

Scroll to Top