Reflection in Java with Examples

Reflection in Java allows a running Java program to examine or modify itself. It lets you inspect classes, interfaces, fields, and methods at runtime. You can also create new objects, invoke methods, and get or set field values dynamically.

Java Server Pages

What is Reflection in Java?

Reflection is a powerful feature in Java. It provides the ability for a Java program to inspect and manipulate its own structure during execution. You can find information about classes, such as their names, methods, and fields, without knowing them at compile time.

Reflection offers several key benefits:

  • Extensibility Features: Frameworks like Spring and Hibernate use reflection. They read annotations and class structures to provide features like dependency injection or object-relational mapping (ORM).
  • Debugging Tools: Debuggers use reflection to inspect object states and method calls at runtime.
  • Testing Frameworks: JUnit uses reflection to find and execute test methods within a class.
  • Dynamic Code Loading: You can load classes dynamically based on user input or configuration. This allows for more flexible applications.
  • Serialization: Libraries that serialize objects to JSON or XML often use reflection to access object fields.

Is Reflection an API?

Reflection is not an external API like a web service or a third-party library. Instead, Reflection is a core feature of the Java language and its standard library. The java.lang.reflect package provides the classes and interfaces that enable this feature. These classes collectively form the Application Programming Interface (API) for using reflection within your Java programs. So, while you use an API to work with reflection, reflection itself is a built-in capability of Java.

Core Reflection Classes

The java.lang.reflect package provides the classes for reflection. Here are the main ones:

  • Class: This is the entry point for reflection. It represents classes and interfaces in a running Java application.
  • Constructor: This class represents a single constructor of a class.
  • Method: This class represents a single method of a class or interface.
  • Field: This class represents a single field (a member variable) of a class or interface.

How to Use Reflection

You start reflection by getting a Class object. There are three common ways to do this.

1. Using Class.forName()

This method is useful when you have the class name as a string.

Java

public class ReflectionClassForName {
    public static void main(String[] args) {
        try {
            Class<?> myClass = Class.forName("java.lang.String");
            System.out.println("Class Name: " + myClass.getName());
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

This code loads the String class. It then prints its full name.

2. Using object.getClass()

If you already have an object instance, you can get its Class object.

Java

public class ReflectionGetObjectClass {
    public static void main(String[] args) {
        String myString = "Hello Reflection";
        Class<?> myClass = myString.getClass();
        System.out.println("Class Name: " + myClass.getName());
    }
}

This example gets the Class object for a String instance.

3. Using .class Literal

This is the simplest way when you know the class at compile time.

Java

public class ReflectionClassLiteral {
    public static void main(String[] args) {
        Class<?> myClass = Integer.class;
        System.out.println("Class Name: " + myClass.getName());
    }
}

This code directly gets the Class object for Integer.

Examples of Reflection in Action

Let us explore practical examples using reflection.

Example 1: Inspecting Class Fields

You can get information about a class fields, including private ones.

Java

import java.lang.reflect.Field;
class Person {
    private String name;
    public int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
}
public class ReflectFields {
    public static void main(String[] args) {
        try {
            Class<?> personClass = Class.forName("Person");

            System.out.println("Public Fields:");
            Field[] publicFields = personClass.getFields(); // Gets public fields
            for (Field field : publicFields) {
                System.out.println("  " + field.getName());
            }

            System.out.println("\nDeclared Fields (including private):");
            Field[] allFields = personClass.getDeclaredFields(); // Gets all declared fields
            for (Field field : allFields) {
                System.out.println("  " + field.getName());
            }

        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

This code retrieves and prints both public and private fields of the Person class.

Example 2: Inspecting Class Methods

You can list all methods in a class.

Java

import java.lang.reflect.Method;
class Calculator {
    public int add(int a, int b) {
        return a + b;
    }

    private void secretMethod() {
        System.out.println("This is a secret method.");
    }
}
public class ReflectMethods {
    public static void main(String[] args) {
        try {
            Class<?> calculatorClass = Class.forName("Calculator");

            System.out.println("Public Methods:");
            Method[] publicMethods = calculatorClass.getMethods(); // Gets public methods, including inherited
            for (Method method : publicMethods) {
                System.out.println("  " + method.getName());
            }

            System.out.println("\nDeclared Methods (including private):");
            Method[] declaredMethods = calculatorClass.getDeclaredMethods(); // Gets all declared methods
            for (Method method : declaredMethods) {
                System.out.println("  " + method.getName());
            }

        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

This example shows how to get both public and all declared methods of a class.

Example 3: Invoking Methods Dynamically

Reflection allows you to call methods at runtime.

Java

import java.lang.reflect.Method;
class Greeter {
    public void sayHello(String name) {
        System.out.println("Hello, " + name + "!");
    }
}
public class InvokeMethod {
    public static void main(String[] args) {
        try {
            Class<?> greeterClass = Class.forName("Greeter");
            Object greeterInstance = greeterClass.getDeclaredConstructor().newInstance(); // Create an instance

            Method sayHelloMethod = greeterClass.getMethod("sayHello", String.class);
            sayHelloMethod.invoke(greeterInstance, "World"); // Invoke the method

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

This code gets the sayHello method and then invokes it on a Greeter object.

Example 4: Accessing and Modifying Private Fields

You can even access and change private fields using reflection. Be careful with this, as it can break encapsulation.

Java

import java.lang.reflect.Field;
class Account {
    private double balance;

    public Account(double balance) {
        this.balance = balance;
    }

    public double getBalance() {
        return balance;
    }
}
public class AccessPrivateField {
    public static void main(String[] args) {
        try {
            Account myAccount = new Account(100.0);
            System.out.println("Initial Balance: " + myAccount.getBalance());

            Field balanceField = Account.class.getDeclaredField("balance");
            balanceField.setAccessible(true); // Allow access to private field

            balanceField.set(myAccount, 200.0); // Set new value
            System.out.println("New Balance: " + myAccount.getBalance());

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

This example shows how to get a private field, make it accessible, and change its value.

When to Use and When to Avoid Reflection

Use Reflection when:

  • You build frameworks that need to interact with user-defined classes.
  • You need to inspect or modify code at runtime for debugging or testing.
  • You create tools that analyze or generate code.

Avoid Reflection when:

  • Performance is critical. Reflection operations are slower than direct calls.
  • You can achieve the same result with normal object-oriented programming.
  • It breaks encapsulation. Direct access to private members can make code harder to maintain and debug.
Avatar photo
Great Learning Editorial Team
The Great Learning Editorial Staff includes a dynamic team of subject matter experts, instructors, and education professionals who combine their deep industry knowledge with innovative teaching methods. Their mission is to provide learners with the skills and insights needed to excel in their careers, whether through upskilling, reskilling, or transitioning into new fields.

Academy Pro Subscription

Grab 50% off
on Top Courses - Free Trial Available

×
Scroll to Top