Java 注解(Annotation)
注解是 Java 5 引入的元数据机制,用于为程序元素提供附加信息。理解注解的使用是掌握现代 Java 开发的关键。本章将详细介绍 Java 中的注解。
注解的概念
什么是注解
注解(Annotation)是一种元数据,用于为代码提供附加信息,不影响程序的执行。
// 使用注解
@Override
public void method() {
// ...
}
@Deprecated
public void oldMethod() {
// ...
}
注解的作用
- 编译时处理:提供信息给编译器
- 运行时处理:通过反射获取注解信息
- 代码生成:工具可以根据注解生成代码
- 文档生成:生成 API 文档
内置注解
@Override
标识方法重写父类方法:
public class Animal {
public void makeSound() {
System.out.println("动物发出声音");
}
}
public class Dog extends Animal {
@Override // 标识重写
public void makeSound() {
System.out.println("汪汪汪");
}
}
好处:
- 编译器检查重写是否正确
- 如果父类方法签名改变,会提示错误
@Deprecated
标识已过时的方法或类:
@Deprecated
public class OldClass {
@Deprecated
public void oldMethod() {
System.out.println("过时的方法");
}
}
// 使用时会提示警告
OldClass obj = new OldClass();
obj.oldMethod(); // 编译器会提示警告
@SuppressWarnings
抑制编译器警告:
@SuppressWarnings("unchecked")
public void method() {
List list = new ArrayList(); // 抑制未检查警告
}
@SuppressWarnings({"unchecked", "deprecation"})
public void method2() {
// 抑制多个警告
}
@SafeVarargs
标识方法使用可变参数是安全的:
@SafeVarargs
public static <T> void method(T... args) {
// ...
}
@FunctionalInterface
标识函数式接口(Java 8+):
@FunctionalInterface
public interface Calculator {
int calculate(int a, int b);
// 只能有一个抽象方法
// int anotherMethod(); // ❌ 错误:函数式接口只能有一个抽象方法
}
元注解
元注解是用于定义注解的注解。
@Target
指定注解可以应用的位置:
import java.lang.annotation.ElementType;
import java.lang.annotation.Target;
@Target({ElementType.METHOD, ElementType.TYPE})
public @interface MyAnnotation {
}
// 可以使用在方法和类上
@MyAnnotation
public class MyClass {
@MyAnnotation
public void method() { }
}
ElementType 值:
TYPE:类、接口、枚举FIELD:字段METHOD:方法PARAMETER:参数CONSTRUCTOR:构造方法LOCAL_VARIABLE:局部变量ANNOTATION_TYPE:注解PACKAGE:包
@Retention
指定注解的保留策略:
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
}
RetentionPolicy 值:
SOURCE:只在源代码中,编译后丢弃CLASS:编译到 .class 文件,运行时不可用(默认)RUNTIME:运行时可用,可以通过反射获取
@Documented
注解信息包含在 JavaDoc 中:
import java.lang.annotation.Documented;
@Documented
public @interface MyAnnotation {
}
@Inherited
注解可以被子类继承:
import java.lang.annotation.Inherited;
@Inherited
public @interface MyAnnotation {
}
@MyAnnotation
public class Parent { }
public class Child extends Parent {
// Child 也继承了 @MyAnnotation
}
@Repeatable
注解可以重复使用(Java 8+):
import java.lang.annotation.Repeatable;
@Repeatable(Roles.class)
public @interface Role {
String value();
}
public @interface Roles {
Role[] value();
}
// 可以重复使用
@Role("管理员")
@Role("用户")
public class User {
}
自定义注解
定义注解
使用 @interface 关键字定义注解:
public @interface MyAnnotation {
String value(); // 注解元素
int count() default 1; // 带默认值
}
// 使用
@MyAnnotation(value = "测试", count = 2)
public class MyClass {
}
注解元素
注解可以有多个元素:
public @interface Author {
String name();
String email();
int year() default 2024;
}
// 使用
@Author(name = "张三", email = "zhangsan@example.com", year = 2023)
public class Book {
}
单值注解
如果注解只有一个元素,可以命名为 value:
public @interface Version {
String value(); // 命名为 value
}
// 使用:可以省略 value =
@Version("1.0")
public class MyClass {
}
// 也可以显式写
@Version(value = "1.0")
public class MyClass2 {
}
注解的使用场景
1. 框架配置
// Spring 框架示例
@Component
public class UserService {
@Autowired
private UserRepository userRepository;
@Transactional
public void saveUser(User user) {
userRepository.save(user);
}
}
2. 数据验证
public class User {
@NotNull
@Size(min = 3, max = 20)
private String username;
@Email
private String email;
@Min(18)
@Max(100)
private int age;
}
3. 测试框架
public class CalculatorTest {
@Test
public void testAdd() {
Calculator calc = new Calculator();
assertEquals(5, calc.add(2, 3));
}
@Before
public void setUp() {
// 测试前准备
}
@After
public void tearDown() {
// 测试后清理
}
}
4. 代码生成
// Lombok 示例
@Data
@Builder
public class User {
private String name;
private int age;
}