Annotations in Java are metadata attached to code elements — classes, methods, fields, parameters, etc.
Example:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface LogExecutionTime {
}
Annotations can be retained at different levels:
Retention Policy | Meaning | Example |
---|---|---|
SOURCE | Only exists in source code (discarded by compiler) | @Override |
CLASS | Stored in the class file (bytecode), but not loaded at runtime | |
RUNTIME | Stored in class file and available via reflection at runtime | @RestController , @Entity |
📥 Step 1: Compilation
- During compilation, annotations are either:
- Discarded (SOURCE), or
- Stored in the class file (CLASS/RUNTIME)
- The class file format (the .class file) has special sections where annotations are stored — inside something called the RuntimeVisibleAnnotations or RuntimeInvisibleAnnotations attribute (part of the class file specification).
📦 Step 2: Storage in Class Files
In the compiled .class
file, annotations are saved as structured metadata in a special section (outside normal bytecode).
This is the same area where method signatures, field types, and method modifiers are stored.
🚀 Step 3: Class Loading in the JVM
When the ClassLoader loads a class, the JVM: ✅ Reads the class metadata (including annotations).
✅ Stores that metadata in the Method Area (now stored in Metaspace).
✅ For RUNTIME annotations, the metadata stays accessible via reflection APIs.
🔎 Step 4: Accessing Annotations at Runtime
When you call methods like:
Method method = MyClass.class.getMethod("myMethod");
LogExecutionTime annotation = method.getAnnotation(LogExecutionTime.class);
The JVM: ✅ Looks into the class metadata in Metaspace.
✅ Finds the LogExecutionTime
annotation entry for myMethod
.
✅ Constructs an annotation proxy object (dynamic object that implements the annotation interface).
✅ Returns that proxy object to your code.
⚙️ What’s Inside the Annotation Proxy?
The proxy is a small dynamically-generated object that: ✅ Implements your annotation interface (e.g., LogExecutionTime
).
✅ Stores the actual annotation values (like attributes inside the annotation).
✅ Provides equals()
, hashCode()
, and toString()
implementations for annotations.
📊 Full Lifecycle Summary
Step | Action |
---|---|
1 | You write the annotation in code |
2 | Compiler embeds it in .class file metadata |
3 | JVM loads class and stores annotations in Metaspace |
4 | Reflection APIs let you access those annotations |
5 | JVM builds annotation proxy objects dynamically when needed |
🧰 Example: Reading a Runtime Annotation
@Retention(RetentionPolicy.RUNTIME)
@interface Example {
String value();
}
public class Demo {
@Example("Hello, Annotation!")
public void test() {}
}
public class Main {
public static void main(String[] args) throws Exception {
Method method = Demo.class.getMethod("test");
Example annotation = method.getAnnotation(Example.class);
System.out.println(annotation.value()); // Hello, Annotation!
}
}
⚠️ Important Limitations
- Annotations are immutable — you can read them but you can’t modify them (the annotation proxy is read-only).
- Reflection is relatively slow compared to normal method calls.
- Only RUNTIME annotations are visible at runtime — annotations with CLASS or SOURCE retention can’t be read via reflection.
🔥 Where in the JVM does this happen?
Component | Role |
---|---|
ClassLoader | Reads annotation metadata from .class files |
Metaspace | Stores annotation metadata alongside class data |
Reflection API | Exposes annotations to user code |
Proxy Generator | Builds annotation proxies on demand |
📜 Bonus: Class File View
If you disassemble a class file with javap -v
, you can actually see the annotations:
javap -v Demo.class
Output (fragment):
RuntimeVisibleAnnotations:
0: #15(#16="Hello, Annotation!")
🚀 Summary
Step | What Happens |
---|---|
Define annotation | In code (@MyAnnotation ) |
Compiler stores | In class file (if CLASS or RUNTIME retention) |
JVM loads | Into Metaspace |
Runtime access | Reflection API (getAnnotation() ) |
Proxy creation | Dynamic proxy implements the annotation interface |