注解(Annotation)是代码里的「标记」,本身不改变逻辑,但可以被编译器、工具或反射读取。

1. 常见内置注解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class BuiltInAnnotationDemo {

@Override // 标记这是重写父类的方法,写错会编译报错
public String toString() {
return "这是重写的方法";
}

@Deprecated // 标记已过时,不推荐使用
public void oldMethod() {
System.out.println("过时的方法");
}

@SuppressWarnings("unused") // 压制编译警告
public void anotherMethod() {
int x = 10; // 没用到会有警告,@SuppressWarnings 压掉
}
}

2. 自定义注解

用 @interface 定义注解,配合 @Retention 和 @Target 指定它的生命周期和适用范围。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

// @Retention 指定保留到什么时候
// SOURCE:只在源码里,编译后丢弃
// CLASS:保留到字节码,运行时丢弃(默认)
// RUNTIME:运行时可用,能被反射读取
@Retention(RetentionPolicy.RUNTIME)

// @Target 指定能用在哪些地方
@Target(ElementType.METHOD)

// 定义注解,成员用「类型 名()」表示
public @interface MyTest {
String value() default "默认值"; // 有默认值
int times() default 1; // 有默认值
}

3. 使用自定义注解

1
2
3
4
5
6
7
8
9
10
11
public class UseAnnotationDemo {
@MyTest(value = "测试登录", times = 2)
public void login() {
System.out.println("执行登录");
}

@MyTest("测试注册") // 只有一个叫 value 的成员时,可以省略 value=
public void register() {
System.out.println("执行注册");
}
}

4. 用反射读取注解

注解配合反射,是很多框架(如 JUnit)的核心机制。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import java.lang.reflect.Method;

public class ReadAnnotationDemo {
public static void main(String[] args) throws Exception {
UseAnnotationDemo demo = new UseAnnotationDemo();
Class<?> cls = demo.getClass();

// 遍历所有方法,找出带 @MyTest 的
for (Method m : cls.getDeclaredMethods()) {
if (m.isAnnotationPresent(MyTest.class)) {
MyTest ann = m.getAnnotation(MyTest.class);

System.out.println("运行测试:" + ann.value() + "(执行 " + ann.times() + " 次)");
for (int i = 0; i < ann.times(); i++) {
m.invoke(demo);
}
System.out.println();
}
}
}
}

输出:

1
2
3
4
5
6
运行测试:测试登录(执行 2 次)
执行登录
执行登录

运行测试:测试注册(执行 1 次)
执行注册

5. 元注解

定义注解时用到的注解:

元注解 作用
@Retention 注解保留到什么时候(SOURCE / CLASS / RUNTIME)
@Target 能用在哪些地方(类、方法、字段、参数…)
@Inherited 子类能否继承
@Documented 是否写入文档

小结

  • 常见内置注解:@Override、@Deprecated、@SuppressWarnings
  • 自定义注解用 @interface,配合 @Retention、@Target
  • 注解 + 反射是框架(JUnit、Spring)的核心机制