Unlocking Java Annotations: What They Are, How They Work, and How to Create Your Own
Java annotations, introduced in Java 5, provide a metadata mechanism to associate information with program elements, enabling documentation generation, compile‑time checks, and runtime processing; this guide explains their purpose, underlying principles, meta‑annotations, common built‑in annotations, and demonstrates how to define and use custom annotations with full code examples.
What Is an Annotation?
Annotation, introduced in Java 5, is a new feature that provides a safe, comment‑like mechanism to associate any information or metadata with program elements (classes, methods, fields, etc.). The annotation adds intuitive documentation that is unrelated to business logic and is used by tools or frameworks.
Annotations can be applied to packages, types, constructors, methods, fields, parameters, and local variables. They are stored in the java.lang.annotation package and do not affect program execution.
Uses of Annotations
1. Documentation generation – e.g., @param, @return. 2. Dependency tracking and configuration replacement, such as Dagger 2 dependency injection. 3. Compile‑time checks, e.g., @Override ensures a method actually overrides a superclass method.
How Annotations Work
At runtime, an annotation is an interface that extends Annotation. The JVM creates a dynamic proxy class (e.g., $Proxy1) for each annotation. When the proxy’s methods are invoked, AnnotationInvocationHandler.invoke retrieves values from a memberValues map, which originates from the Java constant pool.
Meta‑Annotations
The java.lang.annotation package defines four meta‑annotations used when creating custom annotations: @Documented – whether the annotation appears in Javadoc. @Retention – the annotation’s lifecycle (SOURCE, CLASS, RUNTIME). @Target – the program elements the annotation can be applied to (e.g., CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE). @Inherited – whether the annotation is inherited by subclasses.
Retention Policies
RetentionPolicy.SOURCE– discarded by the compiler. RetentionPolicy.CLASS – stored in the class file but not retained at runtime (default). RetentionPolicy.RUNTIME – retained at runtime and accessible via reflection.
Target Elements
ElementType.CONSTRUCTOR– constructors. ElementType.FIELD – fields, enum constants. ElementType.LOCAL_VARIABLE – local variables. ElementType.METHOD – methods. ElementType.PACKAGE – packages. ElementType.PARAMETER – parameters. ElementType.TYPE – classes, interfaces, enums.
Common Built‑In Annotations
@Override
Marks a method that overrides a superclass method; the compiler generates an error if it does not.
@Deprecated
Marks a type or member as deprecated; the compiler warns when it is used.
@SuppressWarnings
Suppresses specified compiler warnings, e.g., @SuppressWarnings("unchecked").
Creating Custom Annotations
Rules
Define the annotation with @interface; it implicitly extends java.lang.Annotation and cannot extend other classes or interfaces.
Members must be public or default visibility.
Member types can be primitive types, String, Enum, Class, other annotations, or arrays of these.
Access annotation data at runtime via Java reflection.
An annotation may have no members, but then it provides little value.
PS: Custom annotations require meta‑annotations.
Example Code
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
/** Fruit name annotation */
@Target(FIELD)
@Retention(RUNTIME)
@Documented
public @interface FruitName {
String value() default "";
} import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
/** Fruit color annotation */
@Target(FIELD)
@Retention(RUNTIME)
@Documented
public @interface FruitColor {
/** Color enum */
public enum Color { BLUE, RED, GREEN };
/** Color attribute */
Color fruitColor() default Color.GREEN;
} import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
/** Fruit provider annotation */
@Target(FIELD)
@Retention(RUNTIME)
@Documented
public @interface FruitProvider {
/** Supplier ID */
public int id() default -1;
/** Supplier name */
public String name() default "";
/** Supplier address */
public String address() default "";
} import java.lang.reflect.Field;
/** Annotation processor */
public class FruitInfoUtil {
public static void getFruitInfo(Class<?> clazz) {
String strFruitName = "水果名称:";
String strFruitColor = "水果颜色:";
String strFruitProvicer = "供应商信息:";
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
if (field.isAnnotationPresent(FruitName.class)) {
FruitName fruitName = (FruitName) field.getAnnotation(FruitName.class);
strFruitName = strFruitName + fruitName.value();
System.out.println(strFruitName);
} else if (field.isAnnotationPresent(FruitColor.class)) {
FruitColor fruitColor = (FruitColor) field.getAnnotation(FruitColor.class);
strFruitColor = strFruitColor + fruitColor.fruitColor().toString();
System.out.println(strFruitColor);
} else if (field.isAnnotationPresent(FruitProvider.class)) {
FruitProvider fruitProvider = (FruitProvider) field.getAnnotation(FruitProvider.class);
strFruitProvicer = " 供应商编号:" + fruitProvider.id()
+ " 供应商名称:" + fruitProvider.name()
+ " 供应商地址:" + fruitProvider.address();
System.out.println(strFruitProvicer);
}
}
}
} import test.FruitColor.Color;
/** Annotation usage */
public class Apple {
@FruitName("Apple")
private String appleName;
@FruitColor(fruitColor = Color.RED)
private String appleColor;
@FruitProvider(id = 1, name = "陕西红富士集团", address = "陕西省西安市延安路89号红富士大厦")
private String appleProvider;
public void setAppleColor(String appleColor) { this.appleColor = appleColor; }
public String getAppleColor() { return appleColor; }
public void setAppleName(String appleName) { this.appleName = appleName; }
public String getAppleName() { return appleName; }
public void setAppleProvider(String appleProvider) { this.appleProvider = appleProvider; }
public String getAppleProvider() { return appleProvider; }
public void displayName() { System.out.println("水果的名字是:苹果"); }
} /** Output result */
public class FruitRun {
public static void main(String[] args) {
FruitInfoUtil.getFruitInfo(Apple.class);
}
}Output: 水果名称:Apple 水果颜色:RED 供应商编号:1 供应商名称:陕西红富士集团 供应商地址:陕西省西安市延安路89号红富士大厦
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Java Interview Crash Guide
Dedicated to sharing Java interview Q&A; follow and reply "java" to receive a free premium Java interview guide.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
