注解(Annotation),也叫元数据,是一种代码级别的说明。是Java 的JDK1.5版本开始引入的一个特性,与类、接口、枚举是在同一个层次。它可以声明在包、类、属性、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释。
编写文档:通过代码里标识的元数据生成文档【生成文档doc文档】
代码分析:通过代码里标识的元数据对代码进行分析【使用反射】
编译检查:通过代码里标识的元数据让编译器能够实现基本的编译检查【Override】
很多框架技术的新版本中,都可以使用注解替代XML配置文件;【SpringBoot】
光用没意思,下面学一下怎么写注解
首先是要声明一个注解,注解的声明形式如下:
public @interface 注解名字 {
注解属性
}
例如我们声明注解类型MyAnnotation.java,如下所示:
public @interface MyAnnotation {
}
非常简单,然后就能用了:

当然这不算完,下面看一下编写注解注意点,首先是我们可以设置注解的修饰目标
注解可以用于不同的目标,例如接口、类、构造方法、方法、属性、类型等;
声明注解时,可以使用JDK中已经定义的注解@Target声明注解修饰的目标;
@Target中使用枚举ElementType表示修饰目标,有如下几种修饰目标:
| 方法 | 方法描述 |
|---|---|
ANNOTATION_TYPE | 表示该注解能用于注解类型; |
CONSTRUCTOR | 表示该注解能用于构造方法; |
FIELD | 表示该注解能用于域; |
LOCAL_VARIABLE | 表示该注解能用于局部变量; |
METHOD | 表示该注解能用于方法: |
PACKAGE | 表示该注解能用于包; |
PARAMETER | 表示该注解能用于方法参数; |
TYPE | 表示该注解能用于类、接口、枚举声明; |
例如MyAnnotation2,为其添加@Target,指定修饰目标为TYPE,即类、接口、枚 举等声明可用;
@Target(value=ElementType.TYPE)
public @interface MyAnnotation2 {
}
测试一下,可以发现不能放在方法上

注意:
@Target()有一个value属性名称,属性值是数组,每一元素是ElementType类型 @Target使用的时候 用小括号,括号内部value= {},{}表示数组,每个元素用逗号隔开
- 1
- 2
解决这个的方式是在ElementType中再加一项,让他可以加在方法上
@Target(value = {ElementType.TYPE,ElementType.METHOD})
public @interface MyAnnotation2 {
}
这样就没问题了

JDK中已经定义了注解@Retention,用来定义注解的声明周期;
使用枚举RetentionPolicy定义生命周期,共有三种情况
| 方法 | 方法描述 |
|---|---|
| SOURCE | 示该注解只在源代码级别保留,编译时就会被忽略: |
| CLASS | 示该洼解编译时被保留,在class文件中存在,但VM将会忽略: |
| RUNTIME | 示该注解被VM保留,所以能在运行时被VM或其他使用反射机制的代码所读取和使用, |
例如编写MyAnnotation3,指定其生命周期为RUNTIME
@Target(value=ElementType.TYPE)
@Retention(value=RetentionPolicy.RUNTIME)
public @interface MyAnnotation3 {
}
使用以下@MyAnnotation3

我们查看编译后的class文件,就找不到@MyAnnotation3了

之前说声明的时候就提到过注解属性,例如注解的声明形式如下:
public @interface 注解名字 {
注解属性
}
注解属性就写在里面,注解属性看起来像个方法,其实是属性,属性类型包括所有基本类型、 String、Class、enum、 Annotation、以上类型的数组形式,注解元素声明形式如下:
public String urlpattern();
public boolean onload();
编写MyAnnotation4.java,添加2个属性,如下所示:
@Target(value=ElementType.TYPE)
@Retention(value=RetentionPolicy.RUNTIME)
public @interface MyAnnotation4 {
public String urlpattern();
public boolean onload();
}
注解中的属性在使用的时候可以指定值,也可以在声明的时候赋默认值;
编写MyAnnotation5,对onload属性赋默认值为false;
@Target(value=ElementType.TYPE)
@Retention(value=RetentionPolicy.RUNTIME)
public @interface MyAnnotation5 {
public String urlpattern() ;
public boolean onload() default false;
}
使用注解非常简单,不管是JDK中内置的已经定义好的注解还是自定义的注解,只要使用 @注解名称(属性值列表)的形式,均可以使用;
例如我们编写 LoginWebComponent中使用上面定义的 MyAnnotaion5,指定了urlpattern及onload属性值:
//onload这个属性可以不给值 因为是默认的false
@MyAnnotation5(urlPattern = "/user/login", onload = false)
public class LoginWebComponent {
public void doPost(String urlPattern, boolean onload) {
System.out.println("请求的urlPattern=" + urlPattern + ",οnlοad=" + onload);
}
}
那我们怎么对注解进行操作呢?比如说获取urlPattern的值到doPost里,直接上面这样写肯定是不行的。
我们需要通过反射来对注解进行应用
比如说获取注解中的属性:
//获取LoginWebComponent的Class对象
Class<?> loginClazz = Class.forName("com.shixun.annotation.LoginWebComponent");
//获取LoginWebComponent类上使用的注解注解对象
MyAnnotation5 annotation5 = loginClazz.getAnnotation(MyAnnotation5.class);
//获取注解的属性值
String urlPattern = annotation5.urlPattern();
boolean onload = annotation5.onload();
// 打印获取到的注解属性
System.out.println("打印获取到的注解属性================");
System.out.println("urlPattern:"+urlPattern+" | onload:"+onload);

也可以用其他方法:
比如再使用获得到的注解属性动态创建LoginWebComponent对象,调用doPost方法
//动态创建LoginWebComponent对象
Object loginInstance = loginClazz.newInstance();
//动态获取LoginWebComponent的doPost方法
Method doPostMethod = loginClazz.getDeclaredMethod("doPost", String.class, boolean.class);
//调用doPost方法
Object result = doPostMethod.invoke(loginInstance, urlPattern, onload);
System.out.println(result);
再比如获取LoginWebComponent类上所有的注解
System.out.println("获取LoginWebComponent类上所有的注解===========================");
Annotation[] annotations = loginClazz.getAnnotations();
for (Annotation annotation : annotations) {
System.out.println(annotation.toString());
}
