注解的解析
就是判断类上、方法上、成员变量上是否存在注解,并把注解里的内容解析出来。
如何解析注解
主要思想:要解析谁上面的注解,就应该先拿到谁。
-
比如要解析类上面的注解,则应该先获取该类的Class对象,再通过Class对象解析其上面的注解。
-
又比如,要解析成员方法上的注解,则应该获取到该成员方法的Method对象,再通过Method对象解析其上面的注解。
-
Class、Method、Field、Constructor都实现了AnnotatedElement接口,它们都拥有解析注解的能力。
AnnotatedElement接口提供了解析注解的方法 说明 public Annotation[] getDeclaredAnnotations() 获取当前对象上面的注解 public T getDeclaredAnnotation(Class annotationClass) 获取指定的注解对象 public boolean isAnnotationPresent(Class annotationClass) 判断当前对象上是否存在某个注解
案例
-
定义一个MyTest注解,要求如
- 包含属性:String value()
- 包含属性:double height() default 165.5
- 包含属性:String[] address();
- 限制注解使用的位置:类和成员方法上
- 指定注解的有效范围:一直到运行时
import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target({ElementType.TYPE,ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) public @interface MyTest { String value(); double height() default 165.5; String[] address(); }
-
定义一个类叫Demo:在类中定义一个go方法,并在该类和其他方法上使用MyTest注解
@MyTest(value = "陈雨季", height = 188.8, address = {"福州", "厦门"}) public class Demo { @MyTest(value = "薛之谦", height = 178.8, address = {"上海", "苏州"}) public void go() { } }
-
定义一个AnnotationTest测试类,解析Demo类中的全部注解。
import org.junit.jupiter.api.Test; import java.lang.reflect.Method; import java.util.Arrays; public class AnnotationTest { //目标:解析注解 @Test public void parseClass() throws Exception { //1. 获取类对象 Class c = Demo.class; //2.使用isAnnotationPresent方法判断该类是否被注解 if (c.isAnnotationPresent(MyTest.class)) { //3. 获取注解对象 MyTest myTest = (MyTest) c.getDeclaredAnnotation(MyTest.class); //4. 获取注解中的属性值 String value = myTest.value(); double height = myTest.height(); String[] address = myTest.address(); //5. 打印 System.out.println(value); System.out.println(height); System.out.println(Arrays.toString(address)); } } @Test public void parseMethod() throws Exception { //1. 获取方法对象 Class c = Demo.class; Method method = c.getDeclaredMethod("go"); //2. 判断该方法是否被注解 if(method.isAnnotationPresent(MyTest.class)){ //3. 获取注解对象 MyTest myTest = method.getDeclaredAnnotation(MyTest.class); //4. 获取注解中的属性值 String value = myTest.value(); double height = myTest.height(); String[] address = myTest.address(); //5. 打印 System.out.println(value); System.out.println(height); System.out.println(Arrays.toString(address)); } } }
注解的作用、应用场景
简易版Junit框架的Test注解
- 自定义一个@MyTest注解,只能直接方法,存活范围是一直都在
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MyTest {
}
-
定义若干个方法,部分方法加上@MyTest注释修饰,部分方法不加
-
模拟一个junit程序,触发了增加@MyTest注解的方法执行
import java.lang.reflect.Method;
public class AnnotationDemo {
public static void main(String[] args) throws Exception {
//1. 获取类对象
Class c = AnnotationDemo.class;
//2. 获取方法对象
Method[] methods = c.getMethods();
//3. 遍历方法对象,判断方法上是否有MyTest注解
for (Method method : methods) {
//判断方法上是否有MyTest注解
if (method.isAnnotationPresent(MyTest.class)) {
//有注解,执行方法
method.invoke(new AnnotationDemo());
}
}
}
//junit:void、无参数、公开的方法
@MyTest
public void test1() {
System.out.println("test1");
}
public void test2() {
System.out.println("test2");
}
@MyTest
public void test3() {
System.out.println("test3");
}
public void test4() {
System.out.println("test4");
}
}
最后启动程序,只有被标记MyTest注解的方法执行了
而在注解的属性参数上,可以设置一个count参数,用于控制方法执行的次数,其默认值可以设置为1
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MyTest {
int count() default 1;
}
import java.lang.reflect.Method;
public class AnnotationDemo {
public static void main(String[] args) throws Exception {
//1. 获取类对象
Class c = AnnotationDemo.class;
//2. 获取方法对象
Method[] methods = c.getMethods();
//3. 遍历方法对象,判断方法上是否有MyTest注解
for (Method method : methods) {
//判断方法上是否有MyTest注解
if (method.isAnnotationPresent(MyTest.class)) {
MyTest myTest = method.getAnnotation(MyTest.class);
int count = myTest.count();
for (int i = 0; i < count; i++){
//有注解,执行方法
method.invoke(new AnnotationDemo());
}
}
}
}
//junit:void、无参数、公开的方法
@MyTest(count = 5)
public void test1() {
System.out.println("test1");
}
public void test2() {
System.out.println("test2");
}
@MyTest
public void test3() {
System.out.println("test3");
}
public void test4() {
System.out.println("test4");
}
}