说明:注解可以理解为另一种形式的配置,可用于在类上、方法上等,标志是“@”,如重写方法上的“@Override”就是一种注解。这里我通过一个实例,来介绍自定义注解和java元注解(@Target、@Retention)的使用
自定义注解
在idea中鼠标右键创建一个类,选择“Annotation”可创建一个注解;我这里创建了一个MyAnnotate注解,设置了一个int类型的times属性,默认值是1
/**
* 自定义注解
*
* @author 10765
*/
public @interface MyAnnotate {
// 定义属性times,表示次数,默认值为1
int times() default 1;
}
@Target注解
java元注解的一种,表示当前注解可使用的类型,查看java源码,可以看到有以下待选:
public enum ElementType {
// 类、接口(包括注释类型)或枚举声明
TYPE,
// 字段声明(包括枚举常量)
FIELD,
// 方法声明
METHOD,
// 形式参数声明
PARAMETER,
// 构造函数声明
CONSTRUCTOR,
// 局部变量声明
LOCAL_VARIABLE,
// 注解类型声明
ANNOTATION_TYPE,
// 包声明
PACKAGE,
/**
* 类型参数声明
*
* 自JDK1.8出现
*/
TYPE_PARAMETER,
/**
* 使用类型
*
* 自JDK1.8出现
*/
TYPE_USE,
/**
* 模块声明
*
* 自JDK9出现
*/
MODULE
}
如上面我自定义的注解,我想只能用于方法上,就可以设置为“@Target(ElementType.METHOD)”
/**
* 自定义注解
* @author 10765
*/
// 指定该注解只能用于方法上
@Target(ElementType.METHOD)
public @interface MyAnnotate {
// 定义属性times,表示次数,默认值为1
int times() default 1;
}
@Retention注解
表示当前注解存活,或者说可使用的阶段,默认是存活在字节码阶段。查看java源码,有以下待选:
public enum RetentionPolicy {
/**
* 编译器将丢弃注释
*/
SOURCE,
/**
* 注解将由编译器记录在类文件中,但不需要在运行时由 VM 保留。这是默认行为。
*/
CLASS,
/**
* 注解将由编译器记录在类文件中,并由 VM 在运行时保留,以便可以反射方式读取它们。
*/
RUNTIME
}
我先不作设置,用实例执行以下我的注解,看下效果
实例
先创建一个学生系统的操作Demo类,并在方法上添加注解,以后使用,想达到的效果是仅执行带有注解的方法,并且根据注解的times值,执行对应的次数
/**
* 学生操作
*/
public class StudentOperate {
public void save() {
System.out.println("save running......");
}
public void delete() {
System.out.println("delete running......");
}
@MyAnnotate
public void update() {
System.out.println("update running......");
}
@MyAnnotate(times = 3)
public void get() {
System.out.println("get running......");
}
}
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class Test {
public static void main(String[] args) throws Exception {
// 获取StudentOperate类的Class对象
Class stuOperateClass = Class.forName("com.essay02.StudentOperate");
// 获取StudentOperate类的所有方法对象
Method[] methodObjs = stuOperateClass.getDeclaredMethods();
// 生成一个Class对象的实例化对象
Object stuOpObj = stuOperateClass.newInstance();
// 遍历所有方法对象
for (Method methodObj : methodObjs) {
// 如果有MyAnnotate注解,就进行操作,否则不作处理
if (methodObj.isAnnotationPresent(MyAnnotate.class)) {
// 获取注解对象
MyAnnotate annotation = methodObj.getAnnotation(MyAnnotate.class);
// 获取注解的属性值times
int times = annotation.times();
// 根据属性值循环执行该方法
for (int i = 0; i < times; i++) {
methodObj.invoke(stuOpObj);
}
}
}
}
}
可以看到,没有执行结果。分析:因为注解的保留策略(@Retention)没有设置,默认保留到字节码阶段,运行时丢弃了,故没有达到预期结果。
查看一下程序的字节码文件
设置注解保留策略为运行时,再执行一遍
/**
* 自定义注解
* @author 10765
*/
// 指定该注解只能用于方法上
@Target(ElementType.METHOD)
// 指定该注解的保留策略为:保留到运行阶段
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotate {
// 定义属性times,表示次数,默认值为1
int times() default 1;
}
最后再试下,保留策略设置为源代码,再运行下查看字节码文件中注解是否还存在
/**
* 自定义注解
* @author 10765
*/
// 指定该注解只能用于方法上
@Target(ElementType.METHOD)
// 指定该注解的保留策略为:保留到源码阶段
@Retention(RetentionPolicy.SOURCE)
public @interface MyAnnotate {
// 定义属性times,表示次数,默认值为1
int times() default 1;
}