注解
在Java中,注解其实就是一种元数据标记,用于在类、方法、字段或其他程序元素前添加特殊标记。注解提供了丰富的方式在Java代码中添加元数据,这些元数据可以在编译时进行检查,也可以在运行时通过反射机制处理。
注解本身是一个特殊的接口,通常继承自 java.lang.annotation
包中的 Annotation
接口。这些接口的定义是元数据的“形状”,定义了注解可以包含的数据结构。
注解包括系统注解和自定义注解,系统注解如 @Override
和 @Deprecated
是Java内置的,用于提供特定的功能,如标识方法覆盖或标记过时的方法。也可以自定义注解,比如spring框架就自定义了大量注解。
注解本身就是一个标记,而提供的功能是要看如何处理。这就像这篇文章,添加了一些tags,这些tags被系统实现为快速搜索。也可以添加一些其他的标签然后自定义一个处理方法,比如用于排序。所有关键还是如何处理。
注解的处理主要有两种方式:
编译期间通过继承
AbstractProcessor
并实现processor
方法运行时通过反射来处理。
元注解
简单来说,元注解就是用来标记注解的。在定义注解时,必须使用元注解 @Retention
、@Target
、@Inherited
和 @Documented
说明注解的作用域、使用范围、是否可继承和是否输出到 API 文档中。
1
2
3
4
5
6
7
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Target(ElementType.TYPE)
@Documented
public @interface MyAnnotation {
String name() default "default";
}
- @Retention:表示保留期,它的值定义了该注解的生命周期。
- @Target:表示适用范围,可以指定作用在注解上的目标元素类型,如类、方法、成员变量等。多个目标类型可以用逗号隔开,如果省略该元素,表示定义的注解可以用在所有的程序元素上。
- @Inherited:表示注解可以被继承,默认情况下,注解不会被继承。如果注解需要被子类继承,可以在定义注解时使用 @Inherited 元注解。
- @Documented:表示注解中的元素可以被 javadoc 工具读取并生成文档。
@Retention
@Retention
用来指定注解的生命周期(源码、class文件、运行时),其可选值如下:
- RetentionPolicy.SOURCE : 注解只存在于编译器处理期间,在编译阶段丢弃,不会在编译输出的 class 文件中出现。这些注解在编译结束之后就不再有任何意义,所以它们不会写入字节码。适用于限制程序员编写代码时使用的注解。@Override, @SuppressWarnings都属于这类注解。
- RetentionPolicy.CLASS : 注解会被编译器记录在 class 文件中,但是在运行时 JVM 不会保留,在类加载的时候丢弃。在字节码文件的处理中有用。注解默认使用这种方式。
- RetentionPolicy.RUNTIME : 注解会被编译器记录在 class 文件中,始终不会丢弃,运行期也保留该注解,因此可以使用反射机制读取该注解的信息。
@Target
@Target
注解指定了注解可以被用来修饰哪些程序元素,例如类、方法、域等。@Target 的取值类型有以下常量:
- ElementType.TYPE:用于标注类、接口、枚举。
- ElementType.CONSTRUCTOR:用于标注构造方法。
- ElementType.FIELD:用于标注成员变量。
- ElementType.METHOD:用于标注方法。
- ElementType.PARAMETER:用于标注参数。
- ElementType.LOCAL_VARIABLE:用于标注局部变量。
- ElementType.ANNOTATION_TYPE:用于标注注解。
- ElementType.PACKAGE:用于标注包。
@Inherited
@Inherited
注解表示标注了此注解的类的子类也会被标注此注解,即:允许子类继承父类注释。
@Documented
@Documented
注解也被称为文档化注解,加上这个注解后,注解的信息就可以被 javadoc 所解析。
定义注解
1
2
3
4
5
6
7
8
9
10
11
12
import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD,ElementType.METHOD})
public @interface MyAnnotation {
// 有默认值
int id() default 0;
// 没有默认值
String value();
}
上面定义一个注解,运行时有效,可以用于方法和成员变量上,允许继承,并可以通过javadoc解析。
使用并处理
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 使用注解
public class Hello {
@MyAnnotation(id=1,value="mmy83")
private String name;
@MyAnnotation(id=2,value="mmy83@126.com")
private String email;
@MyAnnotation(id=3,value="hello")
public void say(){
System.out.println(name);
}
@MyAnnotation("word")
public void helloword(){
System.out.println(name);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
// 处理
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class Main {
public static void main(String[] args) {
try {
//获取所有的类成员变量
Field[] fields = Hello.class.getDeclaredFields();
for (Field field : fields) {
//类成员变量
String fieldName = field.getName();
//注解
Annotation[] fieldAnnotations = field.getAnnotations();
for (Annotation annotation : fieldAnnotations) {
Class<? extends Annotation> annotationType = annotation.annotationType();
String annotationSimpleName = annotationType.getSimpleName();
if (annotationType.equals(MyAnnotation.class)) {
MyAnnotation myAnnotation = field.getAnnotation(MyAnnotation.class);
System.out.printf(" 成员变量: %s, 注解:%s, id: %d, value: %s \n" ,fieldName, annotationSimpleName,myAnnotation.id(),myAnnotation.value());
}
}
}
//反射遍历所有方法
Method[] methods = Hello.class.getDeclaredMethods();
for (Method method : methods) {
String methodName = method.getName();
Annotation[] methodAnnotations = method.getAnnotations();
for(Annotation annotation : methodAnnotations) {
Class<? extends Annotation> annotationType = annotation.annotationType();
String annotationSimpleName = annotationType.getSimpleName();
if (annotationType.equals(MyAnnotation.class)) {
MyAnnotation myAnnotation = method.getAnnotation(MyAnnotation.class);
System.out.printf(" 成员方法: %s, 注解:%s, id: %d, value: %s \n" ,methodName, annotationSimpleName,myAnnotation.id(),myAnnotation.value());
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
1
2
3
4
成员变量: name, 注解:MyAnnotation, id: 1, value: mmy83
成员变量: email, 注解:MyAnnotation, id: 2, value: mmy83@126.com
成员方法: helloword, 注解:MyAnnotation, id: 0, value: word
成员方法: say, 注解:MyAnnotation, id: 3, value: hello
注: 反射方式处理要求
@Retention(RetentionPolicy.RUNTIME)