通过反射和注解的方式执行其他类的main方法
在上一篇《通过反射和配置文件的方式执行其他类的main方法》中,用的是配置文件来指定的全限定类名和方法名,本篇采用的是用注解来指定全限定类名和方法名。
1.准备工作
- 被调用main()方法的其他类Calcalator.java
- 自定义注解类Pro.java
- 反射所在的类ReflectTest.java
如下图
最终达到效果依然是,运行ReflectTest类时,Calcalator类的main()方法也被执行了。
2.过程
(1)Calculator类
Calculator.java的main()的方法只有简单一句输出,来检验main()方法被执行了即可。下附代码如下:
package afu.day20200919;
public class Calculator {
public static void main(String[] args) {
System.out.println("Calculator的main()方法执行了");
}
}
(2)自定义注解Pro.java
自定义注解Pro.java文件包含几个部分:
①元注解@Target,用来指明@Pro可以用在那些地方
(TYPE类,METHOD方法,FIELD成员变量)
②元注解@Retention,用来指明@Pro可以保留到哪一阶段
(SOURCE源码,CLASS编译期,RUNTIME运行期)
③抽象方法。
实际上可理解为成员变量。方法名就是成员变量名,方法的返回值就是成员变量的取值。
所以,当我们有一个Pro注解的对象pro之后,直接用pro.className和pro.methodName就能得到注解上记录的对应值“day12.Calculator”和“main”。
下附代码如下:
package afu.day20200919;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(value = {ElementType.TYPE})
@Retention(value = RetentionPolicy.RUNTIME)
public @interface Pro {
String className();
String methodName();
}
(3)ReflectTest类
ReflectTest类,反射来获取自定义注解的对象。下附代码如下,执行就完事儿。
package afu.day20200919;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
@Pro(className = "day12.Calculator", methodName = "main")
public class ReflectTest {
public static void main(String[] args) throws Exception {
//1.通过当前类的字节码对象,判断当前类上是否有自定义的Pro注解
Class reflectTestClass = ReflectTest.class;
//2.有的话,获取该自定义注解,并生成对象
if (reflectTestClass.isAnnotationPresent(Pro.class)) {
Annotation annotation = reflectTestClass.getAnnotation(Pro.class);
Pro pro = (Pro) annotation;
//3.通过该注解对象,获取注解的内容className和methodName
String className = pro.className();
String methodName = pro.methodName();
//4.根据全类名className获取对应类字节码对象
Class clazz = Class.forName(className);
//5.根据该字节码对象获取指定方法methodName的Method对象
Method method = clazz.getMethod(methodName, String[].class);
//6.通过Method对象执行该方法
method.invoke(clazz.newInstance(), (Object) new String[5]);
}
}
}
酱!!!
3.注意
(1) 自定义注解
自定义注解本质上就是接口interface。可以通过反编译命令来查看。
javac Pro.java
javap Pro.class
另外,自定义注解都继承自父接口Annotation,用多态的方式获得Annotation对象后,需要向下转型为我们自定义的注解类型Pro的对象,即:
Pro pro = (Pro) annotation;
因为,父引用不能直接调用子类型特有的成员变量和方法。
String className();和String methodName()是我们自定义的,父接口中Annotation肯定是没有的。