On this page
Reflection Basics
Reflection allows inspection and modification of classes, methods, fields, and constructors at runtime — even private members. It powers frameworks like Spring, Hibernate, and JUnit.
Getting Class Objects
// From an object
String s = "hello";
Class<?> clazz1 = s.getClass();
// From class name
Class<?> clazz2 = Class.forName("java.util.ArrayList");
// From literal
Class<?> clazz3 = String.class;
Class<?> clazz4 = int.class; // primitive
Class<?> clazz5 = int[].class; // array
Inspecting Class Information
Class<?> clazz = Class.forName("java.util.ArrayList");
System.out.println(clazz.getName()); // java.util.ArrayList
System.out.println(clazz.getSimpleName()); // ArrayList
System.out.println(clazz.isInterface()); // false
System.out.println(clazz.getSuperclass()); // class java.util.AbstractList
System.out.println(clazz.getPackageName()); // java.util
Class<?>[] interfaces = clazz.getInterfaces();
for (Class<?> iface : interfaces) {
System.out.println("Implements: " + iface.getName());
}
Fields
public class Person {
private String name;
public int age;
}
Class<?> clazz = Person.class;
// Public fields only
for (Field field : clazz.getFields()) {
System.out.println(field.getName());
}
// All declared fields (including private)
for (Field field : clazz.getDeclaredFields()) {
System.out.println(field.getName() + " : " + field.getType());
}
// Access private field
Person person = new Person();
Field nameField = clazz.getDeclaredField("name");
nameField.setAccessible(true);
nameField.set(person, "Alice");
System.out.println(nameField.get(person)); // Alice
Methods
Class<?> clazz = String.class;
// Public methods (including inherited)
for (Method method : clazz.getMethods()) {
System.out.println(method.getName());
}
// Declared methods only
for (Method method : clazz.getDeclaredMethods()) {
System.out.println(method.getName() + " → " + method.getReturnType());
}
// Invoke method
Method lengthMethod = clazz.getMethod("length");
int len = (int) lengthMethod.invoke("hello"); // 5
Method substringMethod = clazz.getMethod("substring", int.class, int.class);
String sub = (String) substringMethod.invoke("hello", 1, 4); // ell
Constructors
Class<?> clazz = ArrayList.class;
Constructor<?> defaultCtor = clazz.getConstructor();
ArrayList<?> list = (ArrayList<?>) defaultCtor.newInstance();
Constructor<?> sizedCtor = clazz.getConstructor(int.class);
ArrayList<?> list2 = (ArrayList<?>) sizedCtor.newInstance(100);
Creating Objects via Reflection
Class<?> clazz = Class.forName("java.util.HashMap");
Object map = clazz.getDeclaredConstructor().newInstance();
Annotations via Reflection
for (Method method : clazz.getDeclaredMethods()) {
if (method.isAnnotationPresent(Deprecated.class)) {
System.out.println(method.getName() + " is deprecated");
}
}
setAccessible and Module System
Since Java 9, accessing private members across modules requires opens:
Field field = clazz.getDeclaredField("secret");
field.setAccessible(true); // may throw InaccessibleObjectException on Java 17+
For Java 17+, add JVM flag for deep reflection:
java --add-opens java.base/java.lang=ALL-UNNAMED MyApp
Performance Considerations
Reflection is slower than direct calls:
- Method lookup on every call (cache
Methodobjects) - Boxing/unboxing overhead
- Cannot be JIT-optimized as aggressively
// Cache Method objects
private static final Method STRING_LENGTH;
static {
STRING_LENGTH = String.class.getMethod("length");
}
Best Practices
- Use reflection only when necessary — frameworks, testing, generic utilities
- Cache
Class,Method, andFieldobjects — do not look up repeatedly - Prefer public APIs over breaking encapsulation with
setAccessible - Be aware of Java module system restrictions in Java 17+
- Consider alternatives: interfaces, annotations processors, or code generation