在Java编程中,标记(Annotation)是一种用于为代码添加元数据的方式,它不直接影响程序的业务逻辑,但可以被编译器、工具或运行时环境读取并处理,标记自Java 5引入以来,已成为Java生态系统中不可或缺的一部分,广泛应用于框架配置、代码检查、文档生成等多个场景,本文将详细介绍Java中标记的定义、使用方式、内置标记以及自定义标记的实现方法。

标记的基本概念
标记是一种特殊的接口,通过@interface关键字定义,它本质上是一种接口,但与普通接口不同,标记的继承关系隐式继承自java.lang.annotation.Annotation接口,标记可以包含成员变量,但这些成员变量只能是基本类型、String、Class、枚举、注解或这些类型的数组,标记的成员变量在定义时可以指定默认值,使用default关键字修饰。
一个简单的标记定义如下:
public @interface MyAnnotation {
String value() default "";
int count() default 0;
}
在这个例子中,MyAnnotation包含两个成员变量value和count,分别默认为空字符串和0。
标记的使用方式
标记可以通过@标记名的语法附加到代码的各个部分,包括类、方法、字段、参数等,根据标记的保留策略(RetentionPolicy),标记可以在不同阶段被保留:
- SOURCE:标记仅保留在源代码中,编译后会被丢弃。
- CLASS:标记保留在编译后的字节码中,但运行时不可通过反射访问。
- RUNTIME:标记保留到运行时,可通过反射机制读取。
使用@Override标记方法:
@Override
public String toString() {
return "Hello, Annotation!";
}
这里@Override是一个内置标记,用于告知编译器该方法是对父类方法的覆盖,如果方法签名不匹配,编译器会报错。

内置标记及其应用
Java提供了多种内置标记,用于不同的场景:
- @Override:标记方法覆盖父类或实现接口的方法。
- @Deprecated:标记过时的类、方法或字段,使用时编译器会发出警告。
- @SuppressWarnings:抑制编译器警告,可通过
value参数指定警告类型,如@SuppressWarnings("unchecked")。 - @SafeVarargs:用于标记可变参数方法,抑制堆污染相关的警告。
- @FunctionalInterface:标记函数式接口,确保接口中只有一个抽象方法。
这些内置标记简化了代码的维护和检查,
@Deprecated
public void oldMethod() {
System.out.println("This method is deprecated.");
}
调用oldMethod()时,编译器会提示该方法已过时。
自定义标记的实现
开发者可以根据需求自定义标记,自定义标记需要通过@Retention和@Target注解进行配置:
@Retention:指定标记的保留策略,如@Retention(RetentionPolicy.RUNTIME)。@Target:指定标记可附加的位置,如@Target(ElementType.METHOD)表示标记只能用于方法。
定义一个用于记录方法执行时间的标记:
import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Timed {
String value() default "default";
}
使用该标记:

@Timed("login")
public void userLogin() {
// 方法逻辑
}
标记的反射读取
通过反射机制,可以在运行时读取标记信息,读取@Timed标记:
import java.lang.reflect.Method;
public class AnnotationDemo {
public static void main(String[] args) throws NoSuchMethodException {
Method method = AnnotationDemo.class.getMethod("userLogin");
if (method.isAnnotationPresent(Timed.class)) {
Timed timed = method.getAnnotation(Timed.class);
System.out.println("Method: " + timed.value());
}
}
}
输出结果为Method: login,表明成功读取了标记的值。
标记的高级应用
- 标记处理器(Annotation Processor):在编译阶段处理标记,生成额外的代码或文件。 ButterKnife框架通过标记生成视图绑定代码。
- AOP(面向切面编程):通过标记定义切点,实现日志、事务等横切关注点的统一管理,Spring框架的
@Transactional标记用于声明事务。 - 框架配置:许多框架(如Spring、JUnit)大量使用标记简化配置,JUnit的
@Test标记用于标识测试方法。
注意事项
- 标记的继承性:默认情况下,标记不会被继承,但可通过
@Inherited标记实现继承。 - 标记的性能影响:反射读取标记会带来一定的性能开销,应避免在频繁调用的代码中过度使用。
- 标记的命名规范:标记名通常以开头,成员变量名应简洁明了,避免使用复杂类型。
Java标记是一种强大的元数据工具,通过它可以简化代码配置、增强可读性,并支持运行时处理,从内置标记到自定义标记,再到标记处理器和AOP的应用,标记在Java生态系统中发挥着重要作用,合理使用标记,能够显著提升开发效率和代码质量,是Java开发者必须掌握的技能之一。




















