JavaReflection

Reflection

Reflection is the ability of a running Java program to inspect and manipulate its own classes, methods, fields, and constructors — at runtime, without knowing their names at compile time. The API lives in the java.lang.reflect package, and it is how a program can answer questions like “what methods does this object have?” or “can I create an instance of this class whose name I only just read from a config file?”

Ordinary code binds everything at compile time: you write new Car() and call car.drive() because you know, while writing the code, that Car exists and has a drive() method. Reflection flips this around — it lets code discover and invoke members whose identity is only known as data (a string, a file, an annotation) at runtime.

Getting a Class object

Every object in Java carries metadata about its own type, accessible through java.lang.Class. There are three common ways to obtain a Class reference.

Three ways to get a Class object

Java
// 1. From an existing instance
String text = "hello";
Class<?> c1 = text.getClass();

// 2. From a type literal (compile-time known type)
Class<?> c2 = String.class;

// 3. From a fully-qualified class name (only known at runtime!)
Class<?> c3 = Class.forName("java.lang.String");

System.out.println(c1 == c2); // true — the JVM caches one Class per type
System.out.println(c3.getName()); // java.lang.String

Class.forName(String) is the classic entry point for “stringly-typed” class loading — for example, loading a JDBC driver by name, or instantiating a plugin class whose name came from a configuration file.

Inspecting a class

Once you have a Class object, you can list its constructors, methods, and fields — including ones marked private, if you explicitly ask reflection to bypass access checks.

Listing members of a class

Java
import java.lang.reflect.Method;
import java.lang.reflect.Field;
import java.lang.reflect.Constructor;

public class Inspector {
    public static void main(String[] args) throws Exception {
        Class<?> clazz = Class.forName("java.util.ArrayList");

        for (Constructor<?> ctor : clazz.getConstructors()) {
            System.out.println("Constructor: " + ctor);
        }

        for (Method m : clazz.getDeclaredMethods()) {
            System.out.println("Method: " + m.getName());
        }

        for (Field f : clazz.getDeclaredFields()) {
            System.out.println("Field: " + f.getName());
        }
    }
}
Invoking a method reflectively

Once you have a Method object, invoke() calls it on a target instance, passing arguments as an Object[] — the compiler cannot check argument types for you, so mistakes surface as runtime exceptions (InvocationTargetException, IllegalArgumentException) instead of compile errors.

Creating an instance and invoking a method by name

Java
import java.lang.reflect.Method;

public class Greeter {
    private String prefix;

    public Greeter(String prefix) {
        this.prefix = prefix;
    }

    public String greet(String name) {
        return prefix + ", " + name + "!";
    }
}

public class ReflectDemo {
    public static void main(String[] args) throws Exception {
        Class<?> clazz = Class.forName("Greeter");

        // Create an instance via the reflective constructor
        Object greeter = clazz.getConstructor(String.class)
                               .newInstance("Hello");

        // Look up and invoke the "greet" method by name
        Method greetMethod = clazz.getMethod("greet", String.class);
        Object result = greetMethod.invoke(greeter, "World");

        System.out.println(result); // Hello, World!
    }
}
Accessing private members

Reflection can also read and write private fields and call private methods by disabling Java’s normal access checks with setAccessible(true). This is how many testing and serialization libraries peek inside objects without requiring public getters.

Reading a private field

Java
import java.lang.reflect.Field;

Field prefixField = Greeter.class.getDeclaredField("prefix");
prefixField.setAccessible(true); // bypass the private modifier
String value = (String) prefixField.get(greeter);
System.out.println(value); // Hello
Reflection has real costs
Reflective calls are significantly slower than direct calls (no JIT inlining, extra type checks, argument boxing), they bypass compile-time type safety (typos in a method name only fail at runtime), and `setAccessible(true)` can break encapsulation, letting code reach into a class’s internals that were deliberately marked private. Use it deliberately, not as a shortcut around normal API design.
You rarely write this code directly
Application code almost never calls `java.lang.reflect` APIs directly. Instead, the *frameworks* you already use are built on top of reflection: Spring’s dependency injection scans classes for annotated fields and constructors; JUnit discovers and runs `@Test`-annotated methods by reflecting over your test class; Jackson serializes objects to JSON by reflecting over their getters and fields. Understanding reflection helps you understand *how* those tools work, even if you never call `Method.invoke()` yourself.

Reflection API

Purpose

Class.forName(name)

Load a class by fully-qualified name at runtime

getClass()

Get the runtime Class of an existing instance

getDeclaredFields() / getFields()

List a class's fields (declared-only vs. including inherited public ones)

getDeclaredMethods() / getMethods()

List a class's methods

getConstructor(...)

Look up a constructor by parameter types

Method.invoke(target, args...)

Call a method reflectively

Field.setAccessible(true)

Bypass access checks to read/write private members

  • Reflection inspects and manipulates classes, methods, and fields at runtime, via java.lang.reflect.

  • Class.forName(), .getClass(), and Type.class are the three ways to obtain a Class object.

  • Method.invoke() calls a method whose name was only known at runtime, trading compile-time safety for flexibility.

  • Reflection is slower and bypasses encapsulation — use it deliberately, and prefer normal APIs when they suffice.

  • Spring, JUnit, and Jackson are all built on reflection, which is why understanding it clarifies how those frameworks work under the hood.