Java Reflection API
CHEAT SHEET■ annotation■ string/value■ class/type■ keyword
Core Concept
Inspect & manipulate program structure at runtime, even without compile-time knowledge
JVM creates a Class metadata object in Metaspace per loaded .class file
Introspection — examine self | Intercession — modify self
SecurityManager can deny reflective access via SecurityException
enum constructors cannot be instantiated via reflection (protects singleton)
// Get the Class object — 3 ways Class<?> c1 = obj.getClass(); Class<?> c2 = MyClass.class; Class<?> c3 = Class.forName("com.example.MyClass");
Core API — Class<T> Methods
Methods
// all declared (incl. private) Method[] m = c.getDeclaredMethods(); // public incl. inherited Method[] mp = c.getMethods(); // specific method by name + param types Method m = c.getMethod("name", String.class); // invoke (bypass private) m.setAccessible(true); m.invoke(obj, arg1, arg2); m.getName();
Fields
Field[] fields = c.getDeclaredFields(); Field f = c.getDeclaredField("name"); // read & write (even private/final) f.setAccessible(true); Object val = f.get(obj); f.set(obj, newValue); f.getName(); f.getType();
Constructors
Constructor<?>[] cs = c.getDeclaredConstructors(); Constructor<?> ctor = c.getDeclaredConstructor(String.class); ctor.setAccessible(true); Object inst = ctor.newInstance("val");
Hierarchy & Parameters
Class<?> sup = c.getSuperclass(); Class<?>[] ifaces = c.getInterfaces(); // method parameters Parameter[] params = m.getParameters(); for (Parameter p : params) { p.getName(); p.getType(); p.isAnnotationPresent(X.class); }
Custom Annotation — Syntax
import java.lang.annotation.*; @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface MyAnnotation { String value() default ""; int priority() default 1; } // Usage @MyAnnotation(value="x", priority=2) void myMethod() {} // named @MyAnnotation("x") // shorthand if only value() void other() {}
Elements look like methods, behave like fields
Types allowed: primitives, String, Class, enums, annotations, arrays thereof
Elements cannot be null — use "" or 0 as absence sentinel
Single value() element → callers can omit the name
Meta-Annotations
| Annotation | Purpose |
|---|---|
| @Retention | How long annotation lives |
| SOURCE | Discarded after compile |
| CLASS | In .class, not at runtime (default) |
| RUNTIME | Metaspace → available via reflection |
| @Target | Where it can be applied |
| TYPE METHOD FIELD PARAMETER CONSTRUCTOR | |
| @Documented | Include in Javadoc output |
| @Repeatable | Apply same annotation multiple times |
@Repeatable(Roles.class) public @interface Role { String value(); } @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public @interface Roles { Role[] value(); } @Role("ADMIN") @Role("USER") // Java 8+ public class UserService {} Role[] roles = clazz.getAnnotationsByType(Role.class);
AnnotatedElement Interface
All of Class, Method, Field, Constructor, Parameter implement this
// Check presence el.isAnnotationPresent(MyAnn.class); // Get single annotation MyAnn a = el.getAnnotation(MyAnn.class); // Get all annotations on element Annotation[] all = el.getAnnotations(); // Get declared (excl. inherited) Annotation[] dec = el.getDeclaredAnnotations(); // Get repeatable annotations Role[] rs = el.getAnnotationsByType(Role.class);
Read annotation values via their element methods: a.value(), a.priority()
Pattern — Field Validator
Annotation Definition
@Retention(RUNTIME) @Target(FIELD) public @interface Validate { int minLength() default 0; int maxLength() default Integer.MAX_VALUE; boolean notNull() default true; String message() default "Validation failed"; } // Applied on model class User { @Validate(notNull=true, minLength=3, maxLength=20, message="Invalid") private String username; }
Reflection Processor
for (Field f : clazz.getDeclaredFields()) { if (!f.isAnnotationPresent( Validate.class)) continue; f.setAccessible(true); Validate v = f.getAnnotation( Validate.class); Object val = f.get(obj); if (v.notNull() && val==null) errors.add(f.getName()+": null"); if (val instanceof String s) { if (s.length() < v.minLength()) errors.add("too short"); } }
Pattern — Method & Parameter Annotations
Method-Level (Rate Limit)
@Retention(RUNTIME) @Target(METHOD) public @interface RateLimit { int requestsPerMinute() default 60; } // Dispatcher Method m = target.getClass() .getMethod(methodName); if (m.isAnnotationPresent( RateLimit.class)) { RateLimit rl = m .getAnnotation(RateLimit.class); if (count >= rl.requestsPerMinute()) throw new RuntimeException(...); } m.invoke(target, args);
Parameter-Level
// Read param annotations Method m = OrderService.class .getMethod("placeOrder", String.class, int.class); Parameter[] params = m.getParameters(); for (Parameter p : params) { if (p.isAnnotationPresent( NotBlank.class)) { System.out.println( p.getName()+" not blank"); } }
Real-World Framework Usage
| Framework | Annotation | What Reflection Does |
|---|---|---|
| Spring | @Autowired | Scans fields/constructors, injects dependencies (DI container) |
| Spring | @RequestMapping | Scans methods, maps HTTP routes to handler methods |
| JUnit 5 | @Test @BeforeEach | Discovers annotated methods, invokes them in lifecycle order |
| Hibernate | @Entity @Column | Reads field metadata, maps Java fields → DB columns & types |
| Jackson | @JsonProperty | Reads field/method metadata during JSON serialization/deserialization |
| JAX-RS | @GET @Path | Scans classes at startup, builds REST endpoint registry |
Performance
Reflection is slower than direct calls because:
Security checks on every invocation
No JIT inlining possible
Heap allocations for Method/Field objects
Startup scanning (one-time) → overhead acceptable
Hot paths (per-request) → cache or use MethodHandle
// 1. Cache Method/Field objects private static final Method M = MyClass.class.getMethod("doIt"); // 2. MethodHandles — near-native speed MethodHandles.Lookup lk = MethodHandles.lookup(); MethodHandle mh = lk.findVirtual( MyClass.class, "doIt", MethodType.methodType(void.class)); mh.invoke(instance); // 3. LambdaMetafactory (Spring internals) // invokedynamic for hot-path methods
java.lang.reflect · java.lang.annotation · @Retention(RUNTIME) needed for runtime access
getDeclared*() — all access levels, this class onlyget*() — public only, includes inheritedsetAccessible(true) — bypasses private/protected