注解简介
注解是放在Java源码的类、方法、字段、参数前的一种特殊“注释”,用于保存类相关的信息以供反射调用,提供了一种为程序元素提供元数据的方法。注解不能直接干扰程序的运行。注解本身也是一个类,所有的注解都需要继承自java.lang.annotation.Annotation接口。
注解功能
注解的作用主要包括
- 作为特定的标记,告诉编译器一些信息
例如Override注解,编译器会判断是否重写了父类的某个方法,如果没重写,则会编译错误。
- 编译时动态处理,如动态生成代码
例如Lombok的Data,Getter,Setter注解,可以在编译时添加方法。
- 运行时动态处理,作为额外信息的载体
元注解
元注解用于修饰注解的注解,用于注解的定义上。包含Retention,Target,Inherited,Documented四个注解。在使用自定义注解前,需要先了解元注解的意义。
Retention
Retention标记了注解的生命周期。其源码如下,可以看到value为RetentionPolicy类型
1 2 3 4 5 6
| @Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.ANNOTATION_TYPE) public @interface Retention { RetentionPolicy value(); }
|
RetentionPolicy的源码如下,定义了注解的不同的生命周期。
1 2 3 4 5 6 7 8
| public enum RetentionPolicy { SOURCE, CLASS, RUNTIME }
|
Target
Target标记了注解的适用范围。其源码如下,可以看到value为ElementType类型的数组。
1 2 3 4 5 6
| @Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.ANNOTATION_TYPE) public @interface Target { ElementType[] value(); }
|
其中ElementType的源码如下,在这之中定义了注解可以用在的地方。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| public enum ElementType { TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE, ANNOTATION_TYPE, PACKAGE, TYPE_PARAMETER, TYPE_USE, MODULE }
|
Inherited
标识注解是否应当是否允许子类继承
Documented
标识注解是否应当被包含在JavaDoc文档中。
自定义注解
java使用@interface方式定义注解,自定义注解的方法如下。在自定义的过程中需要注意,自定义注解的属性的访问控制符必须是public,同时属性一定需要加括号。
1 2 3 4 5 6 7 8 9 10 11 12
| @Retention(RetentionPolicy.RUNTIME) @Inherited @Documented @Target({ElementType.TYPE,ElementType.FIELD}) public @interface MyAnnotation{ String name() default "test"; int id(); }
|
处理自定义注解
在JAVA中主要使用AnnotatedElement接口定义了如何获取类的信息。其中isAnnotationPresent方法可以用于判断是否被指定的注解是否存在,getAnnotations方法获取所有的注解,getAnnotation获取指定的注解。演示代码如下:
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
| @MyAnnotation(type = "class") public class AnnotationTest {
@MyAnnotation(type = "field") public Object object = new Object();
public static void main(String[] args) { Class<AnnotationTest> clazz = AnnotationTest.class; Annotation[] annotations = clazz.getAnnotations(); for (Annotation annotation : annotations) { if (annotation instanceof MyAnnotation) { System.out.println(((MyAnnotation) annotation).type()); } }
Field field = clazz.getDeclaredFields()[0]; if (field.isAnnotationPresent(MyAnnotation.class)) { MyAnnotation myAnnotation = field.getAnnotation(MyAnnotation.class); System.out.println(myAnnotation.type()); } } }
|
在上述语句中,如果将MyAnnotation的Retention值设为RUNTIME,那么将输出
但是如果将Retention值设为CLASS或者SOURCE,由于在执行时已经没有了注解相关的信息,那么将会没有输出。
参考资料
使用注解