1.2.12 注解
注解
1.2.12.1 概念
注解是一种能被添加到java代码中的元数据,类、方法、变量、参数和包都可以用注解来修饰。注解对于它所修饰的代码并没有直接的影响。这些在标记可以在编译、类加载、运行时被读取,并执行相应的处理。
作用
- 为编译器提供信息 注解能被编译器检测到错误或抑制警告。
- 编译时和部署时的处理 软件工具能处理注解信息从而生成代码,XML文件等等。
- 运行时的处理 有些注解在运行时能被获取到。
分类
- 内置注解
- java.lang 包中包含: @Override、@Deprecated、@SuppressWarnings、@SafeVarargs、@FunctionaInterface
- 元注解: @Retention、@Document、@Target、@Inherited、@Repeatable
- 自定义注解
- 各框架自定义注解: 如 Spring @Bean、@Component、@Service、@Controller 等; Lombok @Get、@Set…
- 用户定义注解
1.2.12.2 JDK 原生注解
常见 JDK lang 包中包含的注解,主要作用是辅助代码检查。
注解 | 说明 |
---|---|
Override | 当前方法覆盖了父类的方法 |
Deprecated | 表示方法或类不再建议使用 |
SuppressWarnings | 编译器忽略特定的编译警告 |
SafeVarargs | 忽略变长参数使用泛型作为形参的警告 |
FunctionalInterface | 用来指定某个接口必须是函数式接口,用在有且仅有一个抽象方法的接口 |
1.2.12.3 元注解
元注解是用于定义其他注解的注解。
注解 | 说明 |
---|---|
Target | 表示注解使用范围 |
Retention | 表示在什么级别保存该注解信息 |
Documented | 将此注解包含再javadoc中 |
Inherited | 子类继承父类中的注解 |
Repeatable | 允许一个注解在一个元素上使用多次 |
Native | 修饰成员变量,表示这个变量可以被本地代码引用,常常被代码生成工具使用 |
Target
@Target(java.lang.annotation.ElementType) 表示注解可使用范围
ElementType | 说明 |
---|---|
TYPE | 接口、类、枚举、注解 |
FIELD | 字段、枚举的常量 |
METHOD | 方法 |
PARAMETER | 方法参数 |
CONSTRUCTOR | 构造函数 |
LOCAL_VARIABLE | 局部变量 |
ANNOTATION_TYPE | 注解 |
PACKAGE | 包 |
Retention
@Retention(RetentionPolicy) 表示需要在什么级别保存该注释信息。
RetentionPolicy | 说明 |
---|---|
SOURCE | 源文件,注解不参与编译,也不在运行期间起作用,相当于注释 |
CLASS | 默认值,编译有效,编译器可以根据注解做一些处理,但 JVM 会忽略它,运行期也无法获取 |
RUNTIME | 运行时有效,会被加载到 Class 对象中,可以通过反射获取注解和值 |
Documented
@Documented 要求 Javadoc 工具将此注解标记元素的注解信息包含在 javadoc 中。
示例
@Documented
public @interface Book {
//书名
String name();
//出版日期
String publishedDate();
//作者
String author();
}
@Book(
name = "Spring in Action",
author = "Craig Walls",
publishedDate = "2008-10-1"
)
public class Varargs {
public static void main(String[] args) {
}
}
- Doc 文档 截图:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dbcAupX9-1627983803208)(…/…/img/annotation_documented.png)]
Inherited
父类使用 @Inherited 的注解会被子类继承
- 定义在类上的注解会被继承
- 定义在方法和属性上的注解,只有在未被重写(或实现)才会被继承
Repeatable
@Repeatable 修饰的注解,可以在同一个地方使用多次。
使用步骤示例
- 定义需要使用 Repeatable 的注解
@Retention(RetentionPolicy.RUNTIME)
@Repeatable(RepeatableContainer.class)
public @interface RepeatableAnnotation {
String value();
}
- 定义使用 Repeatable 容器注解
@Retention(RetentionPolicy.RUNTIME)
public @interface RepeatableContainer {
RepeatableAnnotation[] value();
}
- 使用注解
@RepeatableAnnotation("a")
@RepeatableAnnotation("b")
public class RepeatableTest {
public static void main(String[] args) {
RepeatableAnnotation[] annotationsByType = RepeatableTest.class.getAnnotationsByType(RepeatableAnnotation.class);
for (RepeatableAnnotation repeatableAnnotation : annotationsByType) {
System.out.println(repeatableAnnotation.value());
}
}
}
输出:
a
b
注意事项,上例中注解都需要设定 Retention = RUNTIME,否则无法执行。
Native
使用 @Native 注解修饰成员变量,则表示这个变量可以被本地代码引用,常常被代码生成工具使用。不常使用,了解即可。
1.2.12.4 使用
定义关键字
public @interface CherryAnnotation {
}
注解定义关键字时 @interface,在底层实现上,所有定义的注解都会自动继承 java.lang.annotation.Annotation 接口。
定义注解类型元素
public @interface CherryAnnotation {
public String name();
int age() default 18;
int[] array();
}
注解类型元素的语法非常奇怪,即又有属性的特征(可以赋值),又有方法的特征(打上了一对括号)。但是这么设计是有道理的,我们在后面的章节中可以看到:注解在定义好了以后,使用的时候操作元素类型像在操作属性,解析的时候操作元素类型像在操作方法。
定义注解类型元素时需要注意如下几点:
- 访问修饰符必须为 public,不写默认为 public;
- 该元素的类型只能是基本数据类型、String、Class、枚举类型、注解类型(体现了注解的嵌套效果)以及上述类型的一位数组
- 该元素的名称一般定义为名词,如果注解中只有一个元素,请把名字起为 value(后面使用可以不指定属性名)
- () 不是定义方法参数的地方,也不能在括号中定义任何参数,仅仅只是一个特殊的语法
- default 代表默认值,值必须和第 2 点定义的类型一致
- 如果没有默认值,代表后续使用注解时必须给该类型元素赋值
通过反射获取注解
- 如果我们要获得的注解是配置在方法上的,那么我们要从 Method 对象上获取;如果是配置在属性上,就需要从该属性对应的 Field 对象上去获取,如果是配置在类型上,需要从 Class 对象上去获取。总之在谁身上,就从谁身上去获取!
- isAnnotationPresent(Class<? extends Annotation> annotationClass) 方法是专门判断该元素上是否配置有某个指定的注解;
- getAnnotation(Class<A> annotationClass) 方法是获取该元素上指定的注解。之后再调用该注解的注解类型元素方法就可以获得配置时的值数据;
- 反射对象上还有一个方法 getAnnotations(),该方法可以获得该对象身上配置的所有的注解。它会返回给我们一个注解数组,需要注意的是该数组的类型是 Annotation 类型,这个 Annotation 是 java.lang.annotation 包中的接口。
更详细的自定义注解介绍 https://blog.csdn.net/xsp_happyboy/article/details/80987484