Reflection is Java's ability to inspect and modify classes, interfaces, constructors, methods, and fields at runtime without knowing their names at compile time. Frameworks like Spring Boot, Hibernate, and JUnit rely on Reflection to automatically instantiate beans, map database tables, and run unit tests marked with @Test.
Every loaded type in the JVM is represented by a unique singleton instance of java.lang.Class. You can obtain it in three ways:
public class ReflectionClassDemo {
public static void main(String[] args) throws ClassNotFoundException {
// Way 1: Via .class syntax (fastest, compile-time)
Class> clazz1 = String.class;
// Way 2: Via getClass() on an existing instance
String text = "Veewom";
Class> clazz2 = text.getClass();
// Way 3: Via Class.forName() using fully-qualified name (dynamic)
Class> clazz3 = Class.forName("java.lang.String");
System.out.println("Are all 3 class references identical? " +
(clazz1 == clazz2 && clazz2 == clazz3)); // Prints: true
}
}
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
public class InspectDemo {
public static void main(String[] args) {
Class> clazz = Math.class;
System.out.println("Class Name: " + clazz.getName());
System.out.println("Is Interface: " + clazz.isInterface());
System.out.println("Modifiers: " + Modifier.toString(clazz.getModifiers()));
System.out.println("\nDeclared Methods:");
Method[] methods = clazz.getDeclaredMethods();
for (int i = 0; i < Math.min(5, methods.length); i++) {
System.out.println(" " + methods[i].getReturnType().getSimpleName() + " " +
methods[i].getName() + "()");
}
}
}
Reflection can bypass Java language access controls using setAccessible(true) (though Java 9+ Module System restricts this across strongly encapsulated packages):
import java.lang.reflect.Field;
class SecretVault {
private String secretPin = "7492-Secure";
public void printVaultStatus() {
System.out.println("Vault PIN: " + secretPin);
}
}
public class BreakEncapsulation {
public static void main(String[] args) throws Exception {
SecretVault vault = new SecretVault();
vault.printVaultStatus(); // Prints: 7492-Secure
// Access private field using Reflection
Field pinField = SecretVault.class.getDeclaredField("secretPin");
// Suppress Java language access checking
pinField.setAccessible(true);
// Inspect current private value
System.out.println("Hacked Value: " + pinField.get(vault));
// Overwrite private field value!
pinField.set(vault, "9999-OVERRIDDEN");
vault.printVaultStatus(); // Prints: 9999-OVERRIDDEN!
}
}
import java.lang.reflect.Method;
public class DynamicInvoke {
public static void main(String[] args) throws Exception {
Class> strClass = String.class;
// Look up: public String toUpperCase()
Method toUpperMethod = strClass.getMethod("toUpperCase");
// Invoke on instance "hello veewom"
Object result = toUpperMethod.invoke("hello veewom");
System.out.println("Dynamic Result: " + result); // Prints: HELLO VEEWOM
}
}
| Advantages | Disadvantages |
|---|---|
| Enables dynamic dependency injection (Spring) | Performance penalty (no JIT inlining or caching) |
| Permits plug-in architectures & visual GUI builders | Bypasses compile-time type verification |
| Enables automated JSON/XML object serializers | Breaks encapsulation (modifying private fields) |
| Powers testing frameworks (Mocking, JUnit) | Restricted in Java 9+ Modular systems |
getFields() and getDeclaredFields()?
getFields() returns all public fields of the class and all its superclasses. getDeclaredFields() returns all fields (private, protected, default, and public) declared explicitly by that class, but excludes inherited fields.Accelerate your Java mastery by studying these tightly connected core tutorials:
Processing custom metadata using Reflection.
How ClassLoader loads Class metadata.
Private, protected, and public encapsulation.
Factory and Proxy patterns via Reflection.