写了个执行反射方法的函数,但是却老出问题,捣鼓了下,原来是基本数据类型出了问题,
调用反射中的方法时,需要知道方法的参数类型,
Method getDeclaredMethod(String name, Class>... parameterTypes)
但是因为参数是可变类型,我们要单独下一个执行反射类中方法的工具方法的时候,要用数组来处理,就会出现自动装箱问题,
比如我定义的函数test1(int i,String s),我要调用这个方法,invoke(obj,"test1",1,"hello"),程序自动将int类型的1包装成Integer类型的1,就会出现找不到此方法的异常,
解决办法
包装类的定义下都有一个属性TYPE,根据这个属性有还是没有,可以判断出装箱后的Class是否为包装类的Class,
执行一个函数的前提是你知道它的参数类型是基本的还是包装的,如果有包装类型的参数,那就不需要处理,自动装箱后变成包装类的Class,如果参数中没有包装类,是引用类和基本数据类型,就需要将自动包装的Class转换为基本类型的Class,
下面的transferToPrime函数就起这个作用,(说明,如果是单独的一条语句Method method=c.getDeclaredMethod(String name, Class>... parameterTypes),你就可以手动地写成int.class,double.class,但是抽取成方法时,需要注意
//如果参数中有包装类,将其转换为基本类型,其他类型不变
public Class transferToPrime(Class c, String fieldName) {
Field[] fields = c.getDeclaredFields();
for (int i = 0; i < fields.length; i++) {
if (fields[i].getName().equals(fieldName)) {
try {
return (Class) fields[i].get(null);
} catch (Exception e) {
e.printStackTrace();
}
}
}
return c;
}
//执行方法
public Object invoke(Object obj, String methodName, Object... args) {
Class[] params = new Class[args.length];
for (int i = 0; i < args.length; i++) {
Class f = args[i].getClass();
params[i] = f;
// params[i] = transferToPrime(f, "TYPE");
System.out.println(params[i]);
}
try {
// 从父类和子类所有方法中找
Method m = obj.getClass().getMethod(methodName, params);
return m.invoke(obj, args);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
//执行方法
public Object invoke(String className, String methodName, Object... args) {
Object obj = null;
try {
obj = Class.forName(className).getDeclaredConstructor().newInstance();
return invoke(obj, methodName, args);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
另外,jdk9只有已经把Class类的newInstance方法废弃,虽然还可以用,推荐使用Class的getDeclaredConstructor的newInstance方法,调用类中的无参构造器来创建对象,这也就是无参构造器存在的意义啦.
循环获取指定字段包括父类的,如果没有报异常:
public Field getField(Class clazz,String fieldName){
Field field = null;
for(Class clazz2 = clazz;clazz2 != Object.class;
clazz2=clazz2.getSuperclass()){
try {
field = clazz2.getDeclaredField(fieldName);
} catch (Exception e) { }
}
return field;
}
循环获取方法,包括父类的,如果没有,报错
/**
* 循环遍历当前类及父类的所有方法,寻找指定方法
* @param c要获取的Class对象
* @param methodName方法名
* @param parameterTypesClass类型的可变参数
* @return
*/
public Method getMethod(Class c, String method, Class... parameterTypes) {
for (; c != Object.class; c = c.getSuperclass()) {
try {
Method m = c.getDeclaredMethod(method, parameterTypes);
return m;
} catch (Exception e) {
e.printStackTrace();
}
}
return null;
}