Annotation
annotation就是一些元数据,提供一些数据,但是这些数据又不是程序里的一部分,它对实际的代码块不会有实际的影响。
annotation有很多作用,其中下面三个是比较常见的:
- 生成文档。比如我们想要统计每个方法的时间或者打log。
- 生成代码、XML文件等等。生成代码主要是为了把公共的部分代码抽离出来,较少耦合性,减少冗余重复的代码;实现替代配置文件功能,比如spring中就常用到。
- 在编译时进行格式检查。比如常用的@Override,如果你在某个方法前使用了这个annotation但是这个方法并没有覆盖超类的方法,编译的时候就会出错。
格式
不带参数的:
@Override
public void withoutParams() { ...... };
带参数的
@SuppressWarnings(value = "unchecked")
public void withParams() { ...... };
多个annotations
@Id
@Column(name = "name")
private String name;
重复annotations
@Log(author = "三横兰1", date = "2021-11-18")
@Log(author = "三横兰2", date = "2021-11-18")
public void logSomething() {
}
使用位置
annotation可以用于类、变量、方法、参数等等。
如何定义annotation
我们先看看Spring比较常用的@Configuration定义
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Configuration {
@AliasFor(annotation = Component.class)
String value() default "";
boolean proxyBeanMethods() default true;
}
一般来说,当我们自定义annotation时,首先要使用关键字@interface
标明它是一个annotation,然后标注可以在哪些地方使用(@Target)、什么时候被使用(@Retention),一个最简单的annotation就定义好了。
@Target
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Target {
ElementType[] value();
}
@Target表示在哪些地方可以用,value是一个数组,说明一个annotation可以在多个地方使用,我们看看ElementType都有哪些值
public enum ElementType {
TYPE, /** 类, 接口 (包括注解类型), 或者枚举 */
FIELD, /** 字段 (包括枚举常量) */
METHOD, /** 方法 */
PARAMETER, /** 参数 */
CONSTRUCTOR, /** 构造函数 */
LOCAL_VARIABLE, /** 局部变量 */
ANNOTATION_TYPE, /** 注解 */
PACKAGE, /** 包 */
TYPE_PARAMETER, /** 类型参数 @since 1.8 */
TYPE_USE /** 类型使用 @since 1.8 */
}
比较常用到的是TYPE、FIELD、METHOD、PARAMETER
@Retention
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {
RetentionPolicy value();
}
@Retention表示在什么时候被使用,我们看看RetentionPolicy有哪些值。
public enum RetentionPolicy {
SOURCE, /** Annotations会被编译器遗弃 */
CLASS, /** Annotations在class文件可以只用,但是在运行时会被丢弃 */
RUNTIME /** Annotation在运行时依然可用,所以可以使用反射机制读取信息并对其做一定的处理 */
}
@Documented
@Documented表示该Annotation会被javadoc工具提取成文档
@Repeatable
源码:
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Repeatable {
Class<? extends Annotation> value();
}
如果定义一个可以重复多次使用的注解,那么必须赋值value。我们举个例子看看。
@Log
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Repeatable(Logs.class)
public @interface Log {
String author();
String date();
}
@Logs
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Logs {
Log[] value();
}
在使用的时候我们就可以在一个方法上使用多个@Log注解
@Log(author = "三横兰1", date = "2021-11-18")
@Log(author = "三横兰2", date = "2021-11-18")
public void logSomething() {
}
参数类型
Annotation支持的元素数据类型
public @interface ParamTypes {
int version(); // 基础数据类型(int, short, long, float, double, boolean, byte, char)
String value(); // String
Class<?> clazz(); // Class
TypeEnum type(); // enum
Target annotation(); // Annotation
String[] types(); // 以上类型的数组
}
实践:自定义注解@Log
自定义一个带作者和时间信息的Log注解,该注解只能用于方法上,并且在运行可用。
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Log {
String author();
String date();
}
创建一个类,这个类有一个doSomething()的方法,给这个方法加上Log注解
class LogClass {
@Log(author = "三横兰", date = "2021-11-18")
public void doSomething() {
}
}
对这个注解进行处理,打印出log信息
public class Test {
public static void main(String[] args) throws NoSuchFieldException, SecurityException {
Class<?> clazz = LogClass.class;
for (Method method : clazz.getDeclaredMethods()) {
if (method.isAnnotationPresent(Log.class)) {
for (Annotation annotation : method.getDeclaredAnnotations()) {
if (annotation instanceof Log) {
System.out.println("Log info: \r\nAuthor: " + ((Log) annotation).author()
+ ", version: " + ((Log) annotation).date());
}
}
}
}
}
}
执行main方法后控制台打印出以下信息
Log info:
Author: 三横兰, version: 2021-11-18
本文简单学习了annotation的基础信息和如何创建。
未完待续
蜗牛速度般的学习,慢牛般的成长-
更多文章欢迎关注“三横兰”