JavaSE基础——Java自定义注解原理分析攻略
1. 什么是Java自定义注解
Java自定义注解是指程序员自己定义的一种注解。注解是一种元数据,可以作用于类、方法、字段、参数等元素上,注解会为对应元素添加一些注解程序员自定义的描述信息,用于在程序运行时动态修改程序的行为。
自定义注解需要使用Java中的元注解,即对注解进行注解的注解,来定义自己的注解类型,JavaSE中提供了四种标准类型的元注解:
@Retention
表示注解的生命周期,取值可以是RetentionPolicy.SOURCE
、RetentionPolicy.CLASS
、RetentionPolicy.RUNTIME
。其中,RetentionPolicy.RUNTIME
是注解在运行时也能获取到,一般用于运行时需要进行动态处理的场景。
@Target
表示注解可以用于修饰哪些程序元素,取值可以是ElementType.ANNOTATION_TYPE、ElementType.CONSTRUCTOR、ElementType.FIELD、ElementType.LOCAL_VARIABLE、ElementType.METHOD等。
@Documented
表示该注解类型将被包含在JavaDoc中。
@Inherited
表示如果一个类是被该类型注解过,那么它的派生类也是默认被注解的。
2. 自定义注解的实现步骤
2.1 定义注解类型
Java自定义注解的定义方式和接口类似,使用@interface
关键字定义:
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Author {
String name() default "anonymous";
String date();
int version() default 1;
}
注解类型必须以interface
关键字开头,后面加上@interface
注解。@Retention
表示此注解保留的时间类型,此处表示保留到运行时。@Target
表示此注解使用在什么地方,此处表示可用于类上。
注解定义好后,注意要使用@Retention
注解进行标注,以制定该注解的生命周期,并使用@Target
注解指定作用目标,否则默认会在Java源代码中保留该注解。
2.2 使用注解
定义好注解后,就可以在Java程序中使用它了。以@Author
注解为例:
@Author(name = "Jack", date = "2022-05-01")
public class Test {
//...
}
这里@Author
注解标注在类上,使用name
和date
参数进行设置。
2.3 注解处理器
Java的注解是可用于编译时、加载时或者运行时收集或处理程序信息的标记(metadata)。Java的编译器可以处理Java注解,将注解信息编译进Java字节码中,使用Java反射机制就可以在运行时对注解信息进行处理。
以下示例是一个注解处理器,它可以处理@Author
注解:
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
public class AnnotationProcessor {
public static void process(Object obj) {
Class classObj = obj.getClass();
Annotation annotation = classObj.getAnnotation(Author.class);
if (annotation != null) {
Author author = (Author) annotation;
System.out.println("Author name: " + author.name());
System.out.println("Date: " + author.date());
System.out.println("Version: " + author.version());
}
Field[] fields = classObj.getDeclaredFields();
for (Field field : fields) {
annotation = field.getAnnotation(Author.class);
if (annotation != null) {
Author author = (Author) annotation;
System.out.println("Author name: " + author.name());
System.out.println("Date: " + author.date());
System.out.println("Version: " + author.version());
}
}
}
}
该处理器的功能是获取@Author
注解的信息并输出。在这个处理器中,首先使用getClass()
方法获取需要处理的对象的类对象,然后使用getAnnotation()
和getDeclaredFields()
方法获取类对象和类属性上的注解,并输出注解信息。
下面是示例:
@Author(name = "Jack", date = "2022-05-01")
public class Test {
@Author(name = "Gavin", date = "2022-05-02")
private String testField;
//...
public static void main(String[] args) {
Test t = new Test();
AnnotationProcessor.process(t);
}
}
在这个示例中,Test
类和它的一个私有属性testField
上都使用了@Author
注解。在main
方法中,创建了一个Test
对象,并将其传给了注解处理器。在AnnotationProcessor
类的process()
方法中,通过反射获取了Test
类上的@Author
注解,以及类中声明的testField
属性上的注解,并输出了注解信息。
3. 使用注解优化代码
自定义注解可以用来优化代码,增强编程体验,以下是两个优化示例:
3.1 校验参数
可以使用注解去声明方法的参数并实现校验参数功能,这样可以简化代码和减少冗余的校验代码。下面是一个示例:
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PARAMETER)
public @interface Required {
}
这个注解的作用是用于修饰方法参数,表示该参数必须传入。
使用注解之前:
public void sendMessage(String message) {
if (null == message || message.length() <= 0) {
throw new IllegalArgumentException("message cannot be empty!");
}
//send message...
}
使用注解之后:
public void sendMessage(@Required String message) {
//send message...
}
加上@Required
注解后,原来的参数校验代码就可以省略了,只要在调用方法时传入正确的参数即可。
3.2 单元测试
单元测试是编程过程中必不可少的部分,但有些开发人员习惯将测试代码和业务代码放在一起,或者使用一些命名规范来标识单元测试代码。这种做法显然不够优雅,我们可以使用注解来标识单元测试代码:
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface UnitTest {
}
可以使用@UnitTest
注解在单元测试方法上标注,此时测试代码和业务代码可以清晰地分开。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:javaSE基础java自定义注解原理分析 - Python技术站