一、创建注解
1、注解的基本概念
从JDK5开始,Java增加对元数据的支持,也就是注解,注解与注释是有一定区别的,可以把注解理解为代码里的特殊标记,这些标记可以在编译,类加载,运行时被读取,并执行相应的处理。通过注解,开发人员可以在不改变原有代码和逻辑的情况下在源代码中嵌入补充信息。
2、注解的语法格式
访问修饰符 @interface 注解名称{
注解成员;
}
自定义注解自动继承java.lang.annotation.Annotation接口。
3、一个简单的注解的例子
public @interface Report {
int type() default 0;//属性名:type 类型是int 默认值是0
String level() default "info"; //属性名:level 类型String 默认值“info”
String value() default ""; //属性名:value 类型 String 默认值“”
}
4、注解体的中成员的定义
-
注解体中只有成员变量没有成员方法,而注解的成员变量以“无形参的方法”形式来声明,其方法名定义了该成员变量的名字,其返回值定义了该成员变量的类型。
-
如果注解只有一个参数成员,建议使用参数名为value,而类型只能是八种基本数据类型、String类型、Class类型、enum类型及Annotation类型。
-
使用default关键字声明默认值
5、元注解
有一些注解可以修饰其他注解,这些注解就称为元注解(meta annotation)。Java标准库已经定义了一些元注解,我们只需要使用元注解,通常不需要自己去编写元注解。
@Target
最常用的元注解是@Target
。使用@Target
可以定义Annotation
能够被应用于源码的哪些位置:
- 类或接口:
ElementType.TYPE
; - 字段:
ElementType.FIELD
; - 方法:
ElementType.METHOD
; - 构造方法:
ElementType.CONSTRUCTOR
; - 方法参数:
ElementType.PARAMETER
。
@Target(ElementType.METHOD)
public @interface Report {
int type() default 0;
String level() default "info";
String value() default "";
}
使用@Target注解
@Report(level = "debug",type = 1,value = "woniu") //使用注解并且改变默认值
public void print(){
System.out.print("targer 注解使用");
}
@Retention
另一个重要的元注解@Retention
定义了Annotation
的生命周期:
- 仅编译期:
RetentionPolicy.SOURCE
; - 仅class文件:
RetentionPolicy.CLASS
; - 运行期:
RetentionPolicy.RUNTIME
。
如果@Retention
不存在,则该Annotation
默认为CLASS
。因为通常我们自定义的Annotation
都是RUNTIME
,所以,务必要加上@Retention(RetentionPolicy.RUNTIME)
这个元注解:
@Retention(RetentionPolicy.RUNTIME)
public @interface Report {
int type() default 0;
String level() default "info";
String value() default "";
}
@Repeatable
使用@Repeatable
这个元注解可以定义Annotation
是否可重复。这个注解应用不是特别广泛。
在@Repeatable后面的括号里面我们标注Reports.class,意思是在使用多个@Report注解的时候,这些注解被放在了Reports类型的注解中,参见下面的定义:我们在Reports这个注解中定义了一个数组Report[] value();这个Report[]数据就是用来存放多个@Report注解的。
@Repeatable(Reports.class)
@Target(ElementType.TYPE)
public @interface Report {
int type() default 0;
String level() default "info";
String value() default "";
}
@Target(ElementType.TYPE)
public @interface Reports {
Report[] value();
}
经过@Repeatable
修饰后,在某个类型声明处,就可以添加多个@Report
注解:
@Report(type=1, level="debug")
@Report(type=2, level="warning")
public class Hello {
}
@Inherited
使用@Inherited
定义子类是否可继承父类定义的Annotation
。@Inherited
仅针对@Target(ElementType.TYPE)
类型的annotation
有效,并且仅针对class
的继承,对interface
的继承无效:
@Inherited
@Target(ElementType.TYPE)
public @interface Report {
int type() default 0;
String level() default "info";
String value() default "";
}
在使用的时候,如果一个类用到了@Report
:
@Report(type=1)
public class Person {
}
则它的子类默认也定义了该注解:
public class Student extends Person {
}
二、反射获取Annotation信息
创建一个工程
定义@Report注解
@Inherited
@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Repeatable(Reports.class)
public @interface Report {
int type() default 0;
String level() default "info";
String value() default "";
}
定义@Reports注解
@Inherited //可以继承
@Target({ElementType.TYPE,ElementType.METHOD})//可以修饰类或接口和方法
@Retention(RetentionPolicy.RUNTIME)//运行期存在
public @interface Reports {
Report[] value();
}
定义一个Dog类,使用@Report注解
@Report(type=1,value = "jinmao",level = "abc")
@Report(type=2,value = "bianmu")
public class Dog {
@Report
public void print(){
System.out.println("测试");
}
public void hello(){
System.out.println("hello");
}
}
定义一个Parent类
@Report
public class Parent {
}
定义一个Son类
public class Son extends Parent{
}
定义一个Test类运行
public class Test {
public static void main(String[] args) throws IllegalAccessException, InstantiationException, InvocationTargetException {
//1.获取到Class实例
Class<Dog> dogClass = Dog.class;
//判断类上是否有report的集合
boolean present = dogClass.isAnnotationPresent(Reports.class);
if(present){
//获取Dog类上面的Reports注解
Reports reports = dogClass.getAnnotation(Reports.class);
//循环打印出注解上的属性值
for (Report report : reports.value()) {
System.out.println(report.type()+":"+report.level()+":"+report.value());
}
}
Dog dog = dogClass.newInstance();
//获取类的所有方法
Method[] methods = dogClass.getDeclaredMethods();
for (Method method : methods) {
//如果方法被@Report注解修饰,执行它
if (method.isAnnotationPresent(Report.class)) {
method.invoke(dog,null);
}
}
//测试一下继承的注解
Class<Son> sonClass = Son.class;
//判断son是否继承了Parent的注解@Report
if (sonClass.isAnnotationPresent(Report.class)) {
System.out.println("son 从 parent继承了@Report注解");
}
}
}