1.注解的概念
注解是一种能被添加到java代码中的【元数据,类、方法、变量、参数和包】都可以用注解来修饰。用来定义一个类、属性或一些方法,以便程序能被捕译处理。 相当于一个说明文件,告诉应用程序某个被注解的类或属性是什么,要怎么处理。注解对于它所修饰的代码并没有直接的影响。
2.注解的使用范围
1)为编译器提供信息:注解能被编译器检测到错误或抑制警告。
2)编译时和部署时的处理: 软件工具能处理注解信息从而生成代码,XML文件等等。
3)运行时的处理:有些注解在运行时能被检测到。
3.自定义注解的步骤
第一步:定义注解
第二步:配置注解
第三步:解析注解
4.注解的基本语法
4.1最基本的注解定义
package com.example.demo.config;
public @interface MyAnnotation {
public String name();
int age();
String sex() default "女";
}
注意:自定义注解要用【@interface】
在自定义注解中,其实现部分只能定义注解类型元素!
说明:
a.访问修饰符必须为public,不写默认为public;
b.该元素的类型只能是基本数据类型、String、Class、枚举类型、注解类型以及一维数组;
c.该元素的名称一般定义为名词,如果注解中只有一个元素,名字起为value最好;
d.()不是定义方法参数的地方,也不能在括号中定义任何参数,仅仅只是一个特殊的语法;
e.default
代表默认值,值必须定义的类型一致;
f.如果没有默认值,代表后续使用注解时必须给该类型元素赋值。
4.2常用的元注解
元注解:专门修饰注解的注解。
@Retention:定义注解的保留策略
@Retention(RetentionPolicy.SOURCE) //注解仅存在于源码中,在class字节码文件中不包含
@Retention(RetentionPolicy.CLASS) //默认的保留策略,注解会在class字节码文件中存在,但运行时无法获得,
@Retention(RetentionPolicy.RUNTIME) //注解会在class字节码文件中存在,在运行时可以通过反射获取到@Target:指定被修饰的Annotation可以放置的位置(被修饰的目标)
@Target(ElementType.TYPE) //接口、类
@Target(ElementType.FIELD) //属性
@Target(ElementType.METHOD) //方法
@Target(ElementType.PARAMETER) //方法参数
@Target(ElementType.CONSTRUCTOR) //构造函数
@Target(ElementType.LOCAL_VARIABLE) //局部变量
@Target(ElementType.ANNOTATION_TYPE) //注解
@Target(ElementType.PACKAGE) //包
注:可以指定多个位置,例如:
@Target({ElementType.METHOD, ElementType.TYPE}),也就是此注解可以在方法和类上面使用@Inherited:指定被修饰的Annotation将具有继承性
@Documented:指定被修饰的该Annotation可以被javadoc工具提取成文档.
## 2.读入数据
4.2.1@Target
@Target是专门用来限定某个自定义注解能够被应用在哪些Java元素上面的。
因此,我们可以在使用@Target时指定注解的使用范围,示例如下:
//@MyAnnotation被限定只能使用在类、接口或方法上面
@Target(value = {ElementType.METHOD,ElementType.TYPE})
public @interface MyAnnotation {
public String name();
int age();
String sex() default "女";
}
4.2.2@Retention
@Retention注解,用来修饰自定义注解的生命力。
a.如果一个注解被定义为RetentionPolicy.SOURCE,则它将被限定在Java源文件中,那么这个注解即不会参与编译也不会在运行期起任何作用,这个注解就和一个注释是一样的效果,只能被阅读Java文件的人看到;
b.如果一个注解被定义为RetentionPolicy.CLASS,则它将被编译到Class文件中,那么编译器可以在编译时根据注解做一些处理动作,但是运行时JVM(Java虚拟机)会忽略它,我们在运行期也不能读取到,是默认的;
c.如果一个注解被定义为RetentionPolicy.RUNTIME,那么这个注解可以在运行期的加载阶段被加载到Class对象中。那么在程序运行阶段,我们可以通过反射得到这个注解,并通过判断是否有这个注解或这个注解中属性的值,从而执行不同的程序代码段。
注意:我们实际开发中的自定义注解几乎都是使用的RetentionPolicy.RUNTIME。
使此注解修饰自定义注解生命力的示例如下:
//设置注解的生命力在运行期
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
public String name();
int age();
String sex() default "女";
}
4.2.3@Documented
@Documented注解,是被用来指定自定义注解是否能随着被定义的java文件生成到JavaDoc文档当中。源码如下:
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Documented {
}
4.2.4@Inherited
@Inherited注解,是指定某个自定义注解如果写在了父类的声明部分,那么子类(继承关系)的声明部分也能自动拥有该注解。该注解只对@Target被定义为ElementType.TYPE的自定义注解起作用。下面对其进行详细说明:
(1)该注解作用于整个程序运行中(@Retention(RetentionPolicy.RUNTIME);
(2)该注解只能修饰注解(@Target({ElementType.ANNOTATION_TYPE})),它是一个元注解。
此注解的中文翻译是继承的意思,那么究竟是什么意思呢?通过示例进行演示
第一:先定义两个注解@HasInherited 和 @NoInherited,前者注解包含@Inherited 注解,后者反之
第二:再新建两个类,让其具有继承关系(Father类和Child类),类上暂时不添加任何注解
第三:给父类添加注解@HasInherited,子类不加,然后来获取两个类的注解信息
通过测试类获取注解信息
@Test
public void test() {
// 打印父类注解信息
Annotation[] fatherAnnotations = Father.class.getAnnotations();
log.info("------- 父类 Father 信息 --------");
log.info("父类注解个数:" + fatherAnnotations.length);
for (Annotation fa : fatherAnnotations) {
log.info(fa.annotationType().getSimpleName());
}
// 打印子类注解信息
Annotation[] childAnnotations = Child.class.getAnnotations();
log.info("------- 子类 Child 信息 --------");
log.info("子类注解个数:" + childAnnotations.lengt