Skip to content

注解

注解简介

什么是注解?

注解(Annotation)是 Java 5 引入的特性,用于为代码添加元数据,不直接影响代码执行。

┌─────────────────────────────────────────────────────────────────┐
│                         注解的三个生命周期                        │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│  1. SOURCE    →  仅存在于源码,编译时丢弃                        │
│     示例:@Override, @SuppressWarnings                           │
│                                                                  │
│  2. CLASS     →  编译时保留,运行时丢弃(.class文件中)           │
│     用于:编译时处理,不影响运行时                                 │
│                                                                  │
│  3. RUNTIME   →  运行时保留,可通过反射获取                       │
│     示例:@Autowired, @Transactional                             │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

Java 内置注解

常用注解

注解作用域生命周期说明
@Override方法SOURCE标记重写父类方法
@Deprecated方法/类RUNTIME标记已过时
@SuppressWarnings方法/类SOURCE抑制编译器警告
@FunctionalInterface接口SOURCE标记函数式接口
@SafeVarargs方法RUNTIME抑制可变参数警告
@Retention注解SOURCE指定注解生命周期
@Target注解SOURCE指定注解作用目标

@Override 示例

java
public class Parent {
    public void display() {
        System.out.println("Parent display");
    }
}

public class Child extends Parent {
    @Override  // 编译检查,确保确实重写了父类方法
    public void display() {
        System.out.println("Child display");
    }

    // @Override 编译错误:拼写错误,方法签名不匹配
    // public void displa() { }
}

@SuppressWarnings 示例

java
// 抑制所有警告
@SuppressWarnings("all")
public void method1() { }

// 抑制未检查警告(泛型相关)
@SuppressWarnings("unchecked")
public void method2() {
    List list = new ArrayList();  // raw type
    list.add("test");
}

// 抑制弃用警告
@SuppressWarnings("deprecation")
public void method3() {
    Date date = new Date();  // Date 已弃用
}

// 抑制多种警告
@SuppressWarnings({"unchecked", "deprecation"})
public void method4() { }

元注解(注解的注解)

@Retention

java
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

// 源码级别保留
@Retention(RetentionPolicy.SOURCE)
public @interface SourceOnly { }

// 编译时保留
@Retention(RetentionPolicy.CLASS)
public @interface ClassOnly { }

// 运行时保留(可反射)
@Retention(RetentionPolicy.RUNTIME)
public @interface RuntimeRetention { }

@Target

java
import java.lang.annotation.Target;
import java.lang.annotation.ElementType;

// 只能作用于方法
@Target(ElementType.METHOD)
public @interface MethodOnly { }

// 作用于多种目标
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.TYPE})
public @interface MultiTarget { }

// 注解所有目标(除 PACKAGE)
@Target(ElementType.TYPE_USE)
public @interface AllTypes { }

ElementType 枚举值

说明示例
TYPE类、接口、枚举@MyAnnotation
FIELD字段@MyAnnotation
METHOD方法@MyAnnotation
PARAMETER参数@MyAnnotation
CONSTRUCTOR构造器@MyAnnotation
LOCAL_VARIABLE局部变量@MyAnnotation
ANNOTATION_TYPE注解类型@MyAnnotation
PACKAGE@MyAnnotation

@Inherited

java
@Inherited  // 子类继承父类的此注解
@Retention(RetentionPolicy.RUNTIME)
public @interface InheritedAnnotation { }

@InheritedAnnotation
public class Parent { }

public class Child extends Parent { }  // 自动拥有 @InheritedAnnotation

自定义注解

基本定义

java
import java.lang.annotation.*;

// 定义注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MyAnnotation {
    // 注解属性(类似接口方法)
    String value();  // 必须属性

    int number() default 0;  // 带默认值的属性

    String[] tags() default {};  // 数组属性
}

// 使用
public class Test {
    @MyAnnotation(value = "test", number = 10, tags = {"tag1", "tag2"})
    public void method() { }
}

完整示例

java
// ==================== 定义注解 ====================

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
public @interface ApiDoc {
    String description() default "";
    String author() default "unknown";
    String version() default "1.0";
    String[] tags() default {};
}

// ==================== 使用注解 ====================

@ApiDoc(
    description = "用户登录接口",
    author = "张三",
    version = "2.0",
    tags = {"登录", "用户"}
)
public class UserController {

    @ApiDoc(description = "登录方法")
    public Result login(String username, String password) {
        // 登录逻辑
        return Result.success();
    }
}

// ==================== 读取注解 ====================

public class AnnotationProcessor {

    public static void main(String[] args) throws Exception {
        // 读取类上的注解
        ApiDoc classDoc = UserController.class.getAnnotation(ApiDoc.class);
        if (classDoc != null) {
            System.out.println("类:" + classDoc.description());
            System.out.println("作者:" + classDoc.author());
        }

        // 读取方法上的注解
        Method[] methods = UserController.class.getDeclaredMethods();
        for (Method method : methods) {
            ApiDoc methodDoc = method.getAnnotation(ApiDoc.class);
            if (methodDoc != null) {
                System.out.println("方法:" + method.getName());
                System.out.println("描述:" + methodDoc.description());
            }
        }
    }
}

注解与反射

获取注解信息

java
// ==================== 注解定义 ====================

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@interface RequirePermission {
    String[] value();
}

// ==================== 使用注解 ====================

public class UserService {

    @RequirePermission({"admin", "user:read"})
    public void getUserInfo(Long userId) {
        System.out.println("获取用户信息");
    }

    @RequirePermission({"admin"})
    public void deleteUser(Long userId) {
        System.out.println("删除用户");
    }
}

// ==================== 权限校验框架 ====================

public class SecurityChecker {

    public static void checkPermission(Object target, String methodName) {
        Class<?> clazz = target.getClass();

        try {
            // 获取方法
            Method method = clazz.getDeclaredMethod(methodName);

            // 获取注解
            RequirePermission perm = method.getAnnotation(RequirePermission.class);
            if (perm == null) {
                System.out.println("方法无需权限");
                return;
            }

            // 获取当前用户权限(模拟)
            Set<String> userPermissions = getCurrentUserPermissions();

            // 检查权限
            for (String required : perm.value()) {
                if (!userPermissions.contains(required)) {
                    throw new SecurityException("缺少权限:" + required);
                }
            }

            System.out.println("权限校验通过");

        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
    }

    private static Set<String> getCurrentUserPermissions() {
        // 模拟从Session获取当前用户权限
        return new HashSet<>(Arrays.asList("user:read", "user:write"));
    }
}

// 测试
public class Test {
    public static void main(String[] args) {
        UserService userService = new UserService();
        SecurityChecker.checkPermission(userService, "getUserInfo");
        SecurityChecker.checkPermission(userService, "deleteUser");
    }
}

常用框架注解

Spring 注解

java
// ==================== 组件标注 ====================

@Component          // 通用组件标注
@Service           // 服务层组件
@Repository        // 持久层组件
@Controller        // 控制层组件(Web)
@RestController    // @Controller + @ResponseBody

// ==================== 依赖注入 ====================

@Autowired          // 自动注入(byType)
@Qualifier("name") // 指定注入 bean 名称
@Resource(name="") // 相当于 @Autowired + @Qualifier
@Inject            // JSR-330 标准注解

// ==================== 请求处理 ====================

@RequestMapping     // 请求映射
@GetMapping        // GET 请求
@PostMapping       // POST 请求
@PutMapping        // PUT 请求
@DeleteMapping     // DELETE 请求
@PathVariable       // 路径变量
@RequestParam      // 请求参数

// ==================== 配置 ====================

@Configuration     // 配置类
@Bean              // Bean 定义
@Value             // 注入配置值
@PropertySource    // 加载配置文件

Lombok 注解

java
// ==================== 数据生成 ====================

@Data          // getter/setter/toString/equals/hashCode
@Getter        // 生成 getter
@Setter        // 生成 setter
@ToString      // 生成 toString
@EqualsAndHashCode  // 生成 equals 和 hashCode

// ==================== 构造方法 ====================

@NoArgsConstructor  // 无参构造
@AllArgsConstructor // 全参构造
@RequiredArgsConstructor // 必需参数构造(final 和 @NonNull)

// ==================== 建造者模式 ====================

@Builder    // 生成建造者模式
@Builder.Default  // 建造者默认值

// ==================== 日志 ====================

@Log             // private static final org.slf4j.Logger
@Slf4j
@Log4j
@Log4j2

// ==================== 其他 ====================

@NonNull     // 生成 null 检查
@Cleanup     // 自动关闭资源
@SneakyThrows // 偷偷抛出异常

使用示例

java
// Lombok 示例
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class User {
    @NonNull
    private Long id;

    private String name;

    @Builder.Default
    private Integer age = 0;

    @ToString.Exclude
    private String password;
}

// 使用
User user = User.builder()
    .id(1L)
    .name("张三")
    .age(25)
    .build();
System.out.println(user.getName());  // 自动生成 getter

注解处理器(编译时)

APT 示例

java
// ==================== 注解定义 ====================

@Retention(RetentionPolicy.SOURCE)
@Target(ElementType.CLASS)
public @interface AutoGenerateService {
}

// ==================== 注解处理器 ====================

@SupportedAnnotationTypes("com.example.AutoGenerateService")
@SupportedSourceVersion(SourceVersion.RELEASE_8)
public class ServiceAnnotationProcessor extends AbstractProcessor {

    @Override
    public boolean process(Set<? extends TypeElement> annotations,
                         RoundEnvironment roundEnv) {
        for (Element element : roundEnv.getElementsAnnotatedWith(
                AutoGenerateService.class)) {

            TypeElement typeElement = (TypeElement) element;
            String className = typeElement.getSimpleName().toString();
            String packageName = getPackageName(typeElement);

            // 生成服务类代码
            String generatedCode = generateServiceCode(packageName, className);

            // 写入文件
            writeToFile(packageName, className + "Service", generatedCode);
        }
        return true;
    }

    private String getPackageName(TypeElement typeElement) {
        return processingEnv.getElementUtils()
            .getPackageOf(typeElement).getQualifiedName().toString();
    }

    private String generateServiceCode(String packageName, String className) {
        return "package " + packageName + ";\n" +
               "public class " + className + "Service {\n" +
               "    // Generated code\n" +
               "}\n";
    }
}

总结

注解核心知识点

知识点面试频率实战重要性
@Retention 生命周期⭐⭐⭐⭐⭐⭐⭐⭐⭐
@Target 作用目标⭐⭐⭐⭐⭐⭐⭐⭐
自定义注解⭐⭐⭐⭐⭐⭐⭐⭐⭐
注解与反射⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐
Spring/Lombok 注解⭐⭐⭐⭐⭐⭐⭐⭐

⚠️ 易错点提醒

  1. @Retention(RetentionPolicy.RUNTIME) 才能通过反射获取
  2. 注解属性不能是复杂类型(如 List<T>),只能是基本类型、String、Class、枚举、注解、数组
  3. 注解属性有默认值时,使用注解时可以省略
  4. 注解不支持继承,但可以使用@Inherited让子类继承
  5. 注解不能作用于自己的声明(递归)