问题描述
现存在一个如下类
package com.qianfeng.workone.ReflectWork01;
import com.qianfeng.workone.ReflectWork01.annotation.Process;
public class Calculate {
@Process("添加")
public void add() {
System.out.println("add 方法被调用了");
}
public void edit() {
System.out.println("编辑方法被调用了");
}
@Process("删除")
public void delete() {
System.out.println("删除方法被调用了");
}
}
如何通过反射,输入该方法名或者直接输入注解中的value值就可直接调用对应方法
解题思路
基础思路:
要调用方法就得获得方法对象
要获得方法对象就得获得字节码对象,和实例对象
获得以上条件时候就可以通过方法名调用该方法但是现在存在一个问题就是,如何通过注解的value值来绑定对应的方法从而实现调用?
解决办法就是:首先获得方法对象数组,对每一个数组对象通过isAnnotationPresent()判断是否存在注解,如果存在注解,那么就将注解的value值与输入值进行比较,成功则调用,失败则判断是否为方法名,成功则调用,失败则提示不存在该方法。
高级思路:
在解决上述问题的基础上有两个问题值得考虑:
- 如果增加方法名或者增加注解,源代码能否不变
- 如果换了一个类,在源代码不改变的情况下,能否实现
为解决以上的两个为题,那么就需要封装一个分析类
分析类如何设计?
属性:
Class<?> aClass 获取传入类的字节码对象
private Object obj 为之后的方法调用创建一个公共对象
private Map<String, Method> indeedMethod = new HashMap<>(); 此map集合用于存储方法名和该方法对象
private Map<String, Method> aliasMethod = new HashMap<>(); 此map集合用于存储注解名和该方法名方法:
public void invoke() 通过字节码对象来初始化indeedMethod和aliasMethed
public void ivk(String methodName) 通过传入的字符串来调用对应方法
ivk()方法思路:首先通过methodName来获取aliasMethed中的value如果存在,则直接通过此value来结合indeedMethed获得方法对象从而调用,如果不存在,那么就通过indeedMethed判断是否存在方法对象,存在则调用,不存在则提示该方法不存在;
代码示例
Process注解
package com.qianfeng.workone.ReflectWork01.annotation;
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 Process {
String value();
}
Parser类
package com.qianfeng.workone.ReflectWork01;
import com.qianfeng.workone.ReflectWork01.annotation.Process;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
public class Parser {
//获取类的字节码对象
private Class<?> aClass;
//公共调用对象
private Object obj;
//方法名称和方法对象的map集合(indeed真正的)
private Map<String, Method> indeedMethod = new HashMap<>();
//方法别名和方法名的map集合()(alias别名)
private Map<String,String> aliasMethod = new HashMap<>();
//构造方法
public Parser(Class<?> aClass){
this.aClass = aClass;
this.invoke();
}
//invoke调用
public void invoke(){
try {
obj = aClass.newInstance();
Method[] methods = aClass.getDeclaredMethods();
for (Method method : methods) {
String name = method.getName();
indeedMethod.put(name,method);
Process annotation = method.getAnnotation(Process.class);
if(annotation != null){
String value = annotation.value();
aliasMethod.put(value,name);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
public void ivk(String methodName){
String realMethodName = aliasMethod.get(methodName);
if(realMethodName != null){
Method method = indeedMethod.get(realMethodName);
try {
method.invoke(obj);
} catch (Exception e) {
e.printStackTrace();
}
} else {
Method method = indeedMethod.get(methodName);
if(method != null){
try {
method.invoke(obj);
} catch (Exception e) {
e.printStackTrace();
}
} else {
System.out.println(methodName + ";此方法不存在!");
}
}
}
}
Test01类
package com.qianfeng.workone.ReflectWork01;
import java.util.Scanner;
public class Test01 {
public static void main(String[] args) throws Exception {
Scanner scanner = new Scanner(System.in);
Parser parser = new Parser(Calculate.class);
while(true) {
System.out.print("请输入要执行的方法:");
String value = scanner.next(); // edit
parser.ivk(value);
}
}
}