Java Tutorial 0/145 lessons ~6 min read Lesson 38

    Reflection API

    java reflection API Class.forName getDeclaredMethod invoke setAccessible annotations Spring Hibernate runtime inspection

    Course progress0%
    Focus
    27 guided sections
    Practice signal
    Examples included
    Career prep
    Interview Q&A included

    Introduction

    In the previous lesson, you learned about Java Generics, which provide compile-time type safety and reusable code.

    However, have you ever wondered how frameworks like Spring Boot, Hibernate, JUnit, Jackson, and Mockito work internally?

    For example:

    • How does Spring automatically create beans?
    • How does Hibernate map Java objects to database tables?
    • How does JUnit discover test methods?
    • How does Jackson convert JSON into Java objects?
    • How does Spring inject dependencies without explicitly creating objects?

    The answer is Reflection.

    The Java Reflection API allows a program to inspect and manipulate classes, methods, constructors, fields, and annotations at runtime.

    Reflection is one of the most advanced Java topics and is extensively used in:

    • Spring Framework
    • Spring Boot
    • Hibernate / JPA
    • Jackson
    • JUnit
    • Mockito
    • Dependency Injection
    • ORM Frameworks
    • REST Frameworks
    • Annotation Processing

    Understanding Reflection helps you understand how enterprise Java frameworks work behind the scenes.

    In this lesson, you'll learn:

    • What is Reflection?
    • Why Reflection?
    • Reflection Architecture
    • Class Object
    • Obtaining Class Objects
    • Constructors
    • Methods
    • Fields
    • Annotations
    • Dynamic Object Creation
    • Invoking Methods Dynamically
    • Accessing Private Members
    • Reflection Performance
    • Security Considerations
    • Best Practices
    • Common Mistakes
    • Hands-on Exercises
    • Professional Interview Questions

    What is Reflection?

    Reflection is the ability of a Java program to inspect and manipulate its own structure at runtime.

    Using Reflection, you can:

    • Inspect classes
    • Read fields
    • Invoke methods
    • Create objects
    • Read annotations
    • Discover constructors
    • Access metadata

    Example:

    code
    Running Program
    Reflection
    Inspect Class
    Invoke Methods
    Create Objects

    Unlike normal Java code, Reflection works at runtime.

    Why Reflection?

    Normally:

    code
    Employee employee =
    new Employee();
    employee.display();

    The compiler already knows:

    • Class
    • Method
    • Constructor

    With Reflection:

    code
    Class<?> clazz =
    Class.forName("Employee");

    The class is discovered during execution.

    Benefits:

    • Dynamic Programming
    • Framework Development
    • Dependency Injection
    • Object Mapping
    • Testing
    • Plugin Systems

    Reflection Architecture

    code
    Class
    Constructors
    Methods
    Fields
    Annotations

    The Class object is the entry point to Reflection.

    What is Class<?> ?

    Every Java class has an associated Class object.

    Example:

    code
    String.class

    Or:

    code
    Employee.class

    The Class object stores metadata about the class.

    Obtaining a Class Object

    Method 1

    code
    Class<?> clazz =
    Employee.class;

    Method 2

    code
    Employee employee =
    new Employee();
    Class<?> clazz =
    employee.getClass();

    Method 3

    code
    Class<?> clazz =
    Class.forName(
    "com.company.Employee");

    Class.forName() loads a class dynamically by its fully qualified name.

    Getting Class Information

    code
    Class<?> clazz =
    Employee.class;
    System.out.println(
    clazz.getName());
    System.out.println(
    clazz.getSimpleName());
    System.out.println(
    clazz.getPackageName());

    Output:

    code
    com.company.Employee
    Employee
    com.company

    Accessing Constructors

    code
    Constructor<?>[] constructors =
    Employee.class.getDeclaredConstructors();
    for(Constructor<?> constructor
    : constructors){
    System.out.println(constructor);
    }

    Common methods:

    • getConstructor()
    • getDeclaredConstructor()
    • getConstructors()
    • getDeclaredConstructors()

    Creating Objects Dynamically

    code
    Constructor<Employee> constructor =
    Employee.class.getConstructor();
    Employee employee =
    constructor.newInstance();

    The object is created at runtime without using the new keyword directly.

    Accessing Methods

    code
    Method[] methods =
    Employee.class.getDeclaredMethods();
    for(Method method : methods){
    System.out.println(
    method.getName());
    }

    Invoking Methods

    code
    Method method =
    Employee.class.getMethod(
    "display");
    Employee employee =
    new Employee();
    method.invoke(employee);

    Output:

    code
    Employee Details

    Passing Parameters

    code
    Method method =
    Employee.class.getMethod(
    "setName",
    String.class);
    method.invoke(employee,
    "Rahul");

    Reflection supports methods with parameters.

    Accessing Fields

    code
    Field[] fields =
    Employee.class.getDeclaredFields();
    for(Field field : fields){
    System.out.println(
    field.getName());
    }

    Reading Field Values

    code
    Field field =
    Employee.class.getDeclaredField(
    "name");
    Employee employee =
    new Employee();
    field.setAccessible(true);
    field.set(employee,
    "Jagannath");
    System.out.println(
    field.get(employee));

    Output:

    code
    Jagannath

    Accessing Private Members

    Normally:

    code
    private String password;

    Reflection:

    code
    field.setAccessible(true);

    Allows access to private fields and methods.

    Note: Accessing private members using reflection may be restricted by the module system (Java 9+) or security policies.

    Reading Annotations

    Example:

    code
    @Entity
    class Employee{
    }

    Reflection:

    code
    boolean present =
    Employee.class.isAnnotationPresent(
    Entity.class);
    System.out.println(present);

    Output:

    code
    true

    Frameworks like Spring and Hibernate rely heavily on annotation processing.

    Reflection with Custom Annotations

    code
    @Retention(RetentionPolicy.RUNTIME)
    @interface Author{
    String value();
    }

    Usage:

    code
    @Author("Jagannath")
    class Course{
    }

    Reading:

    code
    Author author =
    Course.class.getAnnotation(
    Author.class);
    System.out.println(
    author.value());

    Reflection and Spring Boot

    Spring scans classes:

    code
    Component
    @Service
    @Repository
    @Controller

    Reflection:

    • Finds annotations
    • Creates objects
    • Injects dependencies
    • Calls constructors

    Without Reflection, Spring's Dependency Injection would not be possible.

    Reflection and Hibernate

    Hibernate reads:

    code
    @Entity
    @Table
    @Id
    @Column

    Reflection is used to:

    • Read fields
    • Create objects
    • Populate entity values
    • Generate SQL mappings

    Reflection Performance

    Normal Method Call:

    code
    employee.display();

    Reflection:

    code
    method.invoke(employee);

    Reflection is generally slower because:

    • Metadata lookup
    • Security checks
    • Dynamic dispatch
    • Runtime resolution

    Therefore, avoid Reflection inside performance-critical loops.

    Security Considerations

    Reflection can:

    • Access private members
    • Modify internal state
    • Bypass encapsulation

    Use it responsibly and only when necessary.

    Best Practices

    Use Reflection Sparingly

    Reflection adds flexibility but also complexity and runtime overhead.

    Cache Reflection Metadata

    Avoid repeatedly looking up methods or fields inside loops.

    Prefer Public APIs

    Use normal method calls whenever possible.

    Handle Reflection Exceptions

    Common exceptions include:

    • ClassNotFoundException
    • NoSuchMethodException
    • NoSuchFieldException
    • InvocationTargetException
    • InstantiationException
    • IllegalAccessException

    Use Framework Support

    In enterprise applications, let frameworks such as Spring and Hibernate manage Reflection whenever possible.

    Common Mistakes

    Using Reflection Unnecessarily

    Direct method calls are simpler, safer, and faster.

    Ignoring Checked Exceptions

    Reflection APIs throw several checked exceptions that must be handled.

    Forgetting setAccessible(true)

    Private members cannot normally be accessed without overriding access checks (subject to module restrictions).

    Repeated Metadata Lookup

    Repeated calls to getDeclaredMethod() or getDeclaredField() can reduce performance.

    Violating Encapsulation

    Reflection should not be used to bypass class design unless there is a valid technical reason.

    Hands-on Exercise

    Create a Java program that:

    1. Loads a class using Class.forName().
    2. Displays the class name and package.
    3. Lists all constructors.
    4. Lists all methods.
    5. Lists all fields.
    6. Dynamically creates an object using reflection.
    7. Invokes a method with parameters.
    8. Reads and updates a private field.
    9. Creates a custom annotation and reads it using Reflection.
    10. Measures the approximate execution time of a normal method call versus a reflective invocation.

    Summary

    The Java Reflection API enables runtime inspection and manipulation of classes, methods, fields, constructors, and annotations. Reflection is the foundation of many enterprise frameworks, including Spring Boot, Hibernate, JUnit, and Jackson. While Reflection provides exceptional flexibility, it should be used carefully because it introduces additional runtime overhead and can bypass normal encapsulation rules.

    Key Takeaways

    • Reflection inspects program metadata at runtime.
    • Class<?> is the entry point to the Reflection API.
    • Classes can be loaded dynamically using Class.forName().
    • Reflection can inspect constructors, methods, fields, and annotations.
    • Objects can be created dynamically using constructors.
    • Methods can be invoked dynamically.
    • Private members can be accessed (subject to access restrictions).
    • Enterprise frameworks rely heavily on Reflection.
    • Reflection is slower than direct method invocation.
    • Cache metadata and avoid unnecessary Reflection in performance-critical code.

    Professional Interview Questions

    1What is Reflection in Java?

    Professional Answer

    Reflection is a Java feature that allows a program to inspect and manipulate classes, constructors, methods, fields, and annotations at runtime. It enables dynamic object creation, method invocation, metadata inspection, and annotation processing. Reflection is widely used by enterprise frameworks such as Spring Boot, Hibernate, JUnit, and Jackson.

    Follow-up Questions

    • Which class is the entry point to Reflection?
    • Why do frameworks use Reflection extensively?

    Interview Tip: Remember: Reflection = Runtime Inspection + Runtime Manipulation.

    2How can you obtain a Class object in Java?

    Professional Answer

    A Class object can be obtained in three common ways: 1. Using the .class literal (for example, Employee.class), 2. Calling getClass() on an object instance, 3. Loading a class dynamically using Class.forName("fully.qualified.ClassName"). Each approach ultimately provides access to the same metadata represented by the Class object.

    Follow-up Questions

    • Which method loads a class dynamically?
    • When is Class.forName() commonly used?

    Interview Tip: The three common approaches are: .class, getClass(), Class.forName().

    3Why is Reflection slower than normal method calls?

    Professional Answer

    Reflection performs runtime metadata lookup, access checks, and dynamic method resolution before invoking members. Direct method calls are resolved more efficiently by the JVM and can benefit from optimizations such as inlining. Because of this additional overhead, Reflection should generally be reserved for framework development, dynamic programming, and infrastructure code rather than performance-critical business logic.

    Follow-up Questions

    • Should Reflection be used inside tight loops?
    • How can Reflection performance be improved?

    Interview Tip: Remember: Direct Call → Fast, Reflection → Flexible but Slower, Cache reflective metadata whenever possible.

    Ready to mark this lesson complete?Track your journey across the entire course.