36.1 Reflection Modern Usage

Use reflection judiciously in a modularized world with strong encapsulation and access controls.

Basic Reflection

import java.lang.reflect.*;

Class<?> clazz = MyClass.class;
Method m = clazz.getMethod("publicMethod", String.class);
Object result = m.invoke(instance, "arg");

Accessing Private Members

Field f = clazz.getDeclaredField("privateField");
f.setAccessible(true);
Object value = f.get(instance);

Module Encapsulation

With JPMS, private reflection requires explicit access:

// May throw InaccessibleObjectException
f.setAccessible(true);

Solution 1: --add-opens at Launch

java --add-opens com.example.module/com.example.internal=ALL-UNNAMED MyApp

Solution 2: opens in module-info

module com.example.module {
  opens com.example.internal to com.framework;
}

Inspecting Annotations

if (clazz.isAnnotationPresent(MyAnnotation.class)) {
  MyAnnotation ann = clazz.getAnnotation(MyAnnotation.class);
  String value = ann.value();
}

Performance

  • Reflection is slower than direct calls.
  • JVM optimizes repeated reflective calls but not as well as direct invocation.
  • Prefer method handles for high-frequency calls.

Guidance

  • Avoid reflection in hot code paths.
  • Use setAccessible(true) sparingly; prefer public APIs.
  • Document reflective access requirements (e.g., for frameworks).
  • Consider method handles for better performance and type safety.