Master Java Annotations: From Basics to Advanced Usage
This article explains what Java annotations are, how to define custom annotations, the built‑in meta‑annotations, annotation attributes, common built‑in annotations, and practical usage scenarios, providing code examples and runtime reflection details for developers.
Introduction
Java annotations are a form of metadata that can be attached directly to source code. They describe relationships between program elements or between code and external resources (e.g., database tables). Annotations were introduced in JDK 5 to replace separate XML‑based metadata, improving maintainability and type safety.
Defining an Annotation
package com.guor.ClientNew;
public @interface MyAnnotation {
// public static final property
int age = 25;
// abstract method defines an element
String name();
}An annotation is essentially an interface that implicitly extends java.lang.annotation.Annotation.
Meta‑annotations
@Retention
Specifies how long the annotation is retained. RetentionPolicy.SOURCE – present only in source code; discarded by the compiler. RetentionPolicy.CLASS – stored in the class file but not available at runtime. RetentionPolicy.RUNTIME – retained at runtime and accessible via reflection.
@Documented
Indicates that the annotation should be included in generated Javadoc.
@Target
Limits the kinds of program elements an annotation can be applied to. ElementType.ANNOTATION_TYPE – another annotation. ElementType.CONSTRUCTOR – a constructor. ElementType.FIELD – a field. ElementType.LOCAL_VARIABLE – a local variable. ElementType.METHOD – a method. ElementType.PACKAGE – a package. ElementType.PARAMETER – a method parameter. ElementType.TYPE – a class, interface, or enum.
@Inherited
If a superclass is annotated with an @Inherited annotation, subclasses inherit the annotation when they do not declare it themselves.
@Repeatable (Java 8)
Allows the same annotation to be applied multiple times to a single element. The repeatable annotation must specify a container annotation.
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Persons {
Person[] value();
}
@Repeatable(Persons.class)
public @interface Person {
String role() default "";
}
@Person(role="CEO")
@Person(role="husband")
@Person(role="father")
@Person(role="son")
public class Man {
String name = "";
}
public static void main(String[] args) {
// Retrieve all annotations on Man
Annotation[] anns = Man.class.getAnnotations();
System.out.println("Total annotations: " + anns.length);
// Cast to the container type
Persons container = (Persons) anns[0];
for (Person p : container.value()) {
System.out.println(p.role());
}
// Safer check using isAnnotationPresent
if (Man.class.isAnnotationPresent(Persons.class)) {
Persons p2 = Man.class.getAnnotation(Persons.class);
for (Person p : p2.value()) {
System.out.println(p.role());
}
}
}Annotation Elements (Attributes)
Elements are declared as parameter‑less methods. The method name becomes the element name and the return type defines the element type. Allowed types are primitive types, String, Class, enums, other annotations, and arrays of these.
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface TestAnnotation {
int id();
String msg();
}
@TestAnnotation(id = 3, msg = "hello annotation")
public class Test {}Elements can have default values using the default keyword:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface TestAnnotation {
int id() default -1;
String msg() default "default message";
}If an annotation defines a single element named value, the element name may be omitted when using the annotation:
public @interface Check {
String value();
}
@Check("hi")
int a; // equivalent to @Check(value="hi")An annotation without any elements can be used without parentheses:
public @interface Perform {}
@Perform
public void testMethod() {}Built‑in Annotations
@Override – signals that a method overrides a superclass method.
@Deprecated – marks a class or method as outdated; the compiler issues a warning when it is used.
@SuppressWarnings – tells the compiler to suppress specific warnings for the annotated element.
@SafeVarargs – suppresses unchecked warnings for var‑args of generic types.
@FunctionalInterface – enforces that the annotated interface has exactly one abstract method, enabling it to be used as a lambda target.
Example of a functional interface:
@FunctionalInterface
interface GreetingService {
void sayMessage(String message);
}
GreetingService greet = msg -> System.out.println("Hello " + msg);Typical Usage Scenarios
Annotations serve as metadata that can be processed:
At compile time – for code generation, documentation, or static analysis.
At runtime – via reflection, enabling frameworks (e.g., Spring, Hibernate) to configure behavior based on annotation values.
Annotations do not alter program logic directly; they provide information to tools and the JVM.
Runtime Representation
When an annotation is accessed at runtime, the JVM creates a dynamic proxy that implements the annotation interface. Calls to the annotation’s methods are delegated to AnnotationInvocationHandler, which retrieves values from an internal map populated from the class file’s constant pool.
Summary
Annotations are special interfaces that extend java.lang.annotation.Annotation and are used to attach metadata to program elements.
They are defined with @interface and can declare elements (attributes) of limited types.
Meta‑annotations such as @Retention, @Target, @Documented, @Inherited, and @Repeatable control the lifecycle, applicability, and repeatability of annotations.
Built‑in annotations ( @Override, @Deprecated, @SuppressWarnings, @SafeVarargs, @FunctionalInterface) aid compilation and framework integration.
Reflection can retrieve annotation data at runtime, but it incurs a performance cost, so use it judiciously.
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.
JavaEdge
First‑line development experience at multiple leading tech firms; now a software architect at a Shanghai state‑owned enterprise and founder of Programming Yanxuan. Nearly 300k followers online; expertise in distributed system design, AIGC application development, and quantitative finance investing.
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.
