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.
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.
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.