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
AnnotationPurpose
@RetentionHow long annotation lives
SOURCEDiscarded after compile
CLASSIn .class, not at runtime (default)
RUNTIMEMetaspace → available via reflection
@TargetWhere it can be applied
TYPE METHOD FIELD PARAMETER CONSTRUCTOR
@DocumentedInclude in Javadoc output
@RepeatableApply 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
FrameworkAnnotationWhat Reflection Does
Spring@AutowiredScans fields/constructors, injects dependencies (DI container)
Spring@RequestMappingScans methods, maps HTTP routes to handler methods
JUnit 5@Test @BeforeEachDiscovers annotated methods, invokes them in lifecycle order
Hibernate@Entity @ColumnReads field metadata, maps Java fields → DB columns & types
Jackson@JsonPropertyReads field/method metadata during JSON serialization/deserialization
JAX-RS@GET @PathScans 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