目录
JAVA中invoke的详细解析
JAVA中invoke是来自于method类的invoke()方法,他可以完成动态调用
Objectinvoke(Object obj, Object... args)调用底层的方法,这 方法对象表示,对指定对象的指定参数
invoke方法的参数,一个是Object类型,也就是调用该方法的对象。
第二个参数是一个可变参数类型,这个可变参数类型是如何能传递一个数组类型,一个为多个参数,另一个为一个数组参数,很明显参数的个数不匹配,我们这时候要将可变参数变成一个参数,
解决方案:
1.将传递进入的参数强转为Object类型
2.将参数重新包装成一个Object数组
public class Aa { public void test(String[] arg){ for (String string : arg) { System.out.println(string); } } @Test public void demo1() throws Exception { //获取字节码对象 Class<Aa> clazz = (Class<Aa>) Class.forName("online.Aa"); //获取一个对象 Constructor con = clazz.getConstructor(); Aa a = (Aa) con.newInstance(); String[] s = new String[]{"aa","bb"}; //获取Method对象 Method method = clazz.getMethod("test", String[].class); //调用invoke方法来调用 //重新包装成一个Obiect数组 method.invoke(a, new Object[]{s}); //强转为Object类型 method.invoke(a,(Object)s); } }当我们将鼠标放到invoke上时,ctrl+鼠标左键进入
@CallerSensitive public Object invoke(Object obj, Object... args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException { if (!override) { if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) { Class<?> caller = Reflection.getCallerClass(); checkAccess(caller, clazz, obj, modifiers); } } MethodAccessor ma = methodAccessor; // read volatile if (ma == null) { ma = acquireMethodAccessor(); } return ma.invoke(obj, args); }invoke()对带有指定参数的指定对象调用,个别参数被自动解包,与基本形参相匹配,基本参数与引用参数都需服从方法调用转换.
参数obj 表示的是基本的方法被调用的对象 args 用于方法的调用
return返回的结果表示的对象和参数 args obj调度方法的结果
解析源码
1.先检查 AccessibleObject的override属性是否为true。
AccessibleObject是Method,Field,Constructor的父类,override属性默认为false,可调用setAccessible方法改变,如果设置为true,则表示可以忽略访问权限的限制,直接调用。
2.如果不是ture,则要进行访问权限检测。用Reflection的quickCheckMemberAccess方法先检查是不是public的,如果不是再用Reflection.getCallerClass(1)方法获
得到调用这个方法的Class,然后做是否有权限访问的校验,校验之后缓存一次,以便下次如果还是这个类来调用就不用去做校验了,直接用上次的 结果,(很奇怪用这种方式缓存,因为这种方式如果下次换个类来调用的话,就不用会缓存了,而再验证一遍,把这次的结果做为缓存,但上一次的缓存结果就被冲 掉了。这是一个很简单的缓冲机制,只适用于一个类的重复调用)。
3.调用MethodAccessor的invoke方法。每个Method对象包含一个root对象,root对象里持有一个 MethodAccessor对象。我们获得的Method独享相当于一个root对象的镜像,所有这类Method共享root里的 MethodAccessor对象,(这个对象由ReflectionFactory方法生成,ReflectionFactory对象在Method类 中是static final的由native方法实例化)。
ReflectionFactory生成MethodAccessor:如果noInflation的属性为true则直接返回MethodAccessorGenerator创建的一个MethodAccessor。
否则返回DelegatingMethodAccessorImpl,并将他与一个NativeMethodAccessorImpl互相引 用。但DelegatingMethodAccessorImpl执行invoke方法的时候又委托给NativeMethodAccessorImpl 了。
再一步深入
4.NativeMethodAccessorImpl的invkoe方法:
调用natiave方法invoke0执行方法调用.
注意这里有一个计数器numInvocations,每调用一次方法+1,当 比 ReflectionFactory.inflationThreshold(15)大的时候,用MethodAccessorGenerator创 建一个MethodAccessor,并把之前的DelegatingMethodAccessorImpl引用替换为现在新创建的。下一次 DelegatingMethodAccessorImpl就不会再交给NativeMethodAccessorImpl执行了,而是交给新生成的 java字节码的MethodAccessor。
MethodAccessorGenerator使用了asm字节码动态加载技术,暂不深入研究。
总结 一个方法可以生成多个Method对象,但只有一个root对象,主要用于持有一个MethodAccessor对象,这个对象也可以认 为一个方法只有一个,相当于是static的。因为Method的invoke是交给MethodAccessor执行的,所以我所想要知道的答案在 MethodAccessor的invoke中,深入MethodAccessor:
Method.invoke()就是调用类中的方法,最简单的用法是可以把方法参数化invoke(class, method) 比如你Test类里有一系列名字相似的方法setValue1、setValue2等等,可以把方法名存进数组v[],
然后循环里invoke(test,v[i]),就顺序调用了全部setValue
