1.问题场景
前端业务需要调用后端方法!
1.引用的类(可以是其他任意类)
这可以是任意希望能被引用的类!
package com.test.item;
public class jsTextUtil {
private int count = 0;
public int test(String i){
System.out.println(count+" | "+i);
return 10;
}
public int test(){
System.out.println("无参方法执行");
return 0;
}
public int test(int a,int b){
System.out.println("2参方法执行 2int");
return 0;
}
public int test(int a,String b){
System.out.println("2参方法执行 int+string");
return 0;
}
public int test(double a,String b){
System.out.println("2参方法执行 double+string");
return 0;
}
}
2.反射工具类(核心方法)
这个工具类可以直接复制去用!但这个工具与一个弊端,就是值只识别基本数据类型的同名重写方法,并对同参数数量方法进行最优转换!
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 反射操作工具
*/
public class ReflexUtil {
Object instance;
public ReflexUtil(){}
/**
* 参数直接传入
* 1.传参数量: 严格符合目标方法参数
* 2.传参顺序: 严格按照目标方法传参顺序
* 3.传参类型为:字符串,和基础数据类型
* 4.传参数据等级:string<char<boole < double<long<float<int<short<byte (数值顺序优先)
* @param className 反射方法路径
* @param methodName 反射方法
* @param args 传入方法参数
* @return
*/
public Object execute(String className,String methodName,String args) {
Class clazz = null;
try {
clazz = Class.forName(className);
instance = clazz.newInstance();//方法实例
String[] args0 = args.split(",");
Method[] methods = clazz.getMethods();//获取所有方法
List<Method> overrideMethods = new ArrayList<>();//重写(同名方法)方法集合
for (Method method0 : methods){
if (!methodName.equals(method0.getName()) || method0.getParameterCount() != args0.length){
continue;
}
overrideMethods.add(method0);
}
if (overrideMethods.size() > 0){
Map<String,Method> methodPower = new HashMap<>();//权限-方法 k-v暂存
Map<String,Object[]> argsPower = new HashMap<>();//权限-传参 k-v暂存
int power = methodMatching(overrideMethods,args0,methodPower,argsPower);// 获取最佳匹配方法
System.out.println("\n============= 匹配方法 start =============");
for (String k:methodPower.keySet()){
System.out.println(k+" "+methodPower.get(k));
}
System.out.println("============= 匹配方法 end =============");
System.out.println("============= 匹配参数组 start =============");
for (String k:argsPower.keySet()){
for (Object obj:argsPower.get(k)){
System.out.print(obj.getClass().getTypeName()+":"+obj+" ");
}
System.out.println();
}
System.out.println("============= 匹配参数组 end =============\n");
System.out.println("最优方法权值:"+power);
Method method = methodPower.get(String.valueOf(power));//最优权限
Object[] args00 = argsPower.get(String.valueOf(power));
System.out.print("最终执行方法:"+method+"\n\r入参:");
for (Object object:args00){
System.out.print(object.getClass().getTypeName()+":"+object+" ");
}
System.out.println("\n\n执行方法打印:");
method.invoke(instance,args00);
}
} catch (ClassNotFoundException e) {
throw new RuntimeException("未找到类异常,请检查类地址: " + className, e);
} catch (InstantiationException e) {
throw new RuntimeException("实例化异常,请检查实例对象: "+ className,e);
} catch (IllegalAccessException e) {
throw new RuntimeException("访问权限的异常,请检查实例对象: "+ className+" 权限", e);
} catch (InvocationTargetException e) {
throw new RuntimeException("调用对象异常",e);
}
return instance;
}
/**
* 排序方法
* @param args 排序数组
* @return
*/
private int rank(int[] args){
for (int i = 0;i < args.length-1;i++){
for (int j = i+1;j < args.length;j++) {
if (args[i] > args[j]) {
args[i] = args[i] + args[j];
args[j] = args[i] - args[j];
args[i] = args[i] - args[j];
}
}
}
return args[0];
}
/**
* @methodMatching 同名同参数数量方法匹配
* @param overrideMethods 重新方法
* @param args0 切割参数
* @param methodPower 权限-方法
* @param argsPower 权限-传参
* string<char<boole < double<long<float<int<short<byte
*/
private int methodMatching(List<Method> overrideMethods, String[] args0,Map<String,Method> methodPower,Map<String,Object[]> argsPower){
int methodCount = 0;
int[] power = new int[overrideMethods.size()]; //方法权限
Object[] args3;
for (Method method:overrideMethods){ //合法方法遍历
int i = 0;
int methodPower2 = 0;
args3 = new Object[args0.length];
try{
Class[] mentodClass = method.getParameterTypes();
for (Class mc:mentodClass){//方法参数遍历配型
switch (mc.getName()){
case "byte"://字节型
args3[i] = Byte.parseByte(args0[i]);
if (args0[i].toString().equals(String.valueOf(Byte.parseByte(args0[i].toString())))){
methodPower2+=19; //字节型
} else if (args0[i].toString().equals(String.valueOf(Short.parseShort(args0[i].toString())))){
methodPower2+=29;
} else if (args0[i].toString().equals(String.valueOf(Integer.parseInt(args0[i].toString())))){
methodPower2+=38;
} else if (args0[i].toString().equals(String.valueOf(Long.parseLong(args0[i].toString())))){
methodPower2+=56;
} else {
methodPower2+=9999;
}
break;
case "short"://短整型
args3[i] = Short.parseShort(args0[i]);
if (args0[i].toString().equals(String.valueOf(Short.parseShort(args0[i].toString())))){
methodPower2+=28;
}else if (args0[i].toString().equals(String.valueOf(Integer.parseInt(args0[i].toString())))){
methodPower2+=38;
} else if (args0[i].toString().equals(String.valueOf(Long.parseLong(args0[i].toString())))){
methodPower2+=56;
} else {
methodPower2+=9999;
}
break;
case "int"://整型
args3[i] = Integer.parseInt(args0[i]);
if (args0[i].toString().equals(String.valueOf(Integer.parseInt(args0[i].toString())))){
methodPower2+=37;
} else if (args0[i].toString().equals(String.valueOf(Long.parseLong(args0[i].toString())))){
methodPower2+=56;
} else {
methodPower2+=9999;
}
break;
case "float"://单精度浮点型
args3[i] = Float.parseFloat(args0[i]);
if (args0[i].toString().equals(String.valueOf(Float.parseFloat(args0[i].toString())))){
methodPower2+=46;
} else if (args0[i].toString().equals(String.valueOf(Double.parseDouble(args0[i].toString())))){
methodPower2+=65;
} else {
methodPower2+=9999;
}
break;
case "login"://常整形
args3[i] = Long.parseLong(args0[i]);
methodPower2+=55;
break;
case "double"://双精度浮点型
args3[i] = Double.parseDouble(args0[i]);
methodPower2+=64;
break;
case "boolean":
args3[i] = Boolean.parseBoolean(args0[i]);
methodPower2+=73;
break;
case "char"://字符型
args3[i] = args0[i].toCharArray()[0];
methodPower2+=82;
break;
default:
args3[i] = String.valueOf(args0[i]);
methodPower2+=91;
}
i++;
}
power[methodCount] = methodPower2;//权限匹配
methodPower.put(String.valueOf(methodPower2),method);//方法权限
argsPower.put(String.valueOf(methodPower2),args3);//参数权限
}catch (Exception e){
System.out.println("类型转换异常!\n异常方法:"+method);
power[methodCount] = 9999;//权限匹配
}
methodCount++;
}
return rank(power);
}
}
3.启动类,调用方法
import org.junit.Test;
public class TestMain {
@Test
public void test(){
try {
System.out.println("------");
new ReflexUtil().execute("com.test.item.jsTextUtil","test","11.2,12.1")
System.out.println("------");
} catch (Exception e) {
System.out.println("反射获取对象错误");
throw new RuntimeException(e);
}
}
}
4.测试打印
------
类型转换异常!
异常方法:public int com.test.item.jsTextUtil.test(int,int)
类型转换异常!
异常方法:public int com.test.item.jsTextUtil.test(int,java.lang.String)
============= 匹配方法 start =============
155 public int com.test.item.jsTextUtil.test(double,java.lang.String)
137 public int com.test.item.jsTextUtil.test(float,java.lang.String)
128 public int com.test.item.jsTextUtil.test(double,double)
92 public int com.test.item.jsTextUtil.test(float,float)
============= 匹配方法 end =============
============= 匹配参数组 start =============
java.lang.Double:11.2 java.lang.String:12.1
java.lang.Float:11.2 java.lang.String:12.1
java.lang.Double:11.2 java.lang.Double:12.1
java.lang.Float:11.2 java.lang.Float:12.1
============= 匹配参数组 end =============
最优方法权值:92
最终执行方法:public int com.test.item.jsTextUtil.test(float,float)
入参:java.lang.Float:11.2 java.lang.Float:12.1
执行方法打印:
参方法执行 float:11.2 float:12.1
------
5.总结
其实反射的应用场景一般遇不到,即使遇到也会用其他的技术手段代替,没必要专门去另外写一个方法!但前端业务通过Ajax调用java方法工具的场景,反射就很不错!