thecodex.expert · The Codex Family of Knowledge
Java

Reflection

Reflection is how Spring finds and calls your @Autowired constructors, and how JUnit discovers and runs your @Test methods — without either framework ever seeing your source code at compile time.

Java 21 LTS Powers Spring & JUnit Last verified:
Canonical Definition

java.lang.reflect provides Class, Method, Field, and Constructor objects that let code inspect and manipulate another class's structure entirely at runtime, without knowing the concrete type at compile time. This is the exact mechanism dependency-injection frameworks like Spring use to construct objects and inject their dependencies, and test frameworks like JUnit use to discover and invoke annotated test methods — both operate on arbitrary user classes without those classes being written with any framework-specific interface in mind.

Inspecting a class at runtime

Class.forName loads a class purely from its name as a String, known only at runtime — the calling code never needed a compile-time reference to Person at all.

JavaInspect.java
Class<?> clazz = Class.forName("com.example.Person");

for (Field field : clazz.getDeclaredFields()) {
    System.out.println(field.getName() + ": " + field.getType());
}

for (Method method : clazz.getDeclaredMethods()) {
    System.out.println(method.getName());
}

Creating instances and calling methods dynamically

setAccessible(true) is needed to invoke a private method reflectively — reflection can genuinely bypass normal access control, which is exactly why it needs to be used carefully and deliberately, not casually.

JavaDynamicInvoke.java
Class<?> clazz = Class.forName("com.example.Person");
Object instance = clazz.getDeclaredConstructor(String.class).newInstance("Alice");

Method getName = clazz.getMethod("getName");
String name = (String) getName.invoke(instance);   // calls instance.getName() dynamically

Method privateMethod = clazz.getDeclaredMethod("internalHelper");
privateMethod.setAccessible(true);   // required to call a private method reflectively
privateMethod.invoke(instance);

The real costs: safety and speed

Reflective calls bypass the compiler's type checking entirely, turning what would be a compile error (a typo in a method name, a wrong argument type) into a runtime exception instead, and they run measurably slower than a direct method call since the JVM cannot apply the same optimizations. Reflection is the right tool specifically for generic frameworks and libraries that must work with arbitrary, unknown-in-advance classes — not for ordinary application logic, which should call methods directly whenever the type is actually known at compile time.

Sources

1
Oracle. The Reflection API, docs.oracle.com/javase/tutorial/reflect/index.html.