Java Method.invoke()反射调用一个方法
java.lang.reflect.Method.invoke() 方法来反射调用一个方法,当然一般只用于正常情况下无法直接访问的方法(比如:private 的方法,或者无法或者该类的对象)。
定义
public native Object invoke(Object receiver, Object... args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException;
参数:
第一个参数是方法属于的对象(如果是静态方法,则可以直接传 null)
第二个可变参数是该方法的参数
返回值:
Object
异常:
如果调用的方法有抛出异常,异常会被 java.lang.reflect.InvocationTargetException 包一层
源码分析
public final class Method extends AccessibleObject implements GenericDeclaration, Member { // ... private volatile MethodAccessor methodAccessor; // For sharing of MethodAccessors. This branching structure is // currently only two levels deep (i.e., one root Method and // potentially many Method objects pointing to it.) private Method root; // ... public Object invoke(Object obj, Object... args)throws IllegalAccessException, IllegalArgumentException,InvocationTargetException { if (!override) { if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) { Class caller = Reflection.getCallerClass(1); Class targetClass = ((obj == null || !Modifier.isProtected(modifiers)) ? clazz : obj.getClass()); boolean cached; synchronized (this) { cached = (securityCheckCache == caller) && (securityCheckTargetClassCache == targetClass); } if (!cached) { Reflection.ensureMemberAccess(caller, clazz, obj, modifiers); synchronized (this) { securityCheckCache = caller; securityCheckTargetClassCache = targetClass; } } } } if (methodAccessor == null) acquireMethodAccessor(); return methodAccessor.invoke(obj, args); } // NOTE that there is no synchronization used here. It is correct // (though not efficient) to generate more than one MethodAccessor // for a given Method. However, avoiding synchronization will // probably make the implementation more scalable. private void acquireMethodAccessor() { // First check to see if one has been created yet, and take it // if so MethodAccessor tmp = null; if (root != null) tmp = root.getMethodAccessor(); if (tmp != null) { methodAccessor = tmp; return; } // Otherwise fabricate one and propagate it up to the root tmp = reflectionFactory.newMethodAccessor(this); setMethodAccessor(tmp); } // ... }
Method.invoke()实际上并不是自己实现的反射调用逻辑,而是委托给sun.reflect.MethodAccessor来处理。 每个实际的Java方法只有一个对应的Method对象作为root,。这个root是不会暴露给用户的,而是每次在通过反射获取Method对象时新创建Method对象把root包装起来再给用户。在第一次调用一个实际Java方法对应得Method对象的invoke()方法之前,实现调用逻辑的MethodAccessor对象还没创建;等第一次调用时才新创建MethodAccessor并更新给root,然后调用MethodAccessor.invoke()真正完成反射调用。
例子
public class MethodInvoke extends BaseTestClass { private boolean checkString(String s) { printFormat("checkString: %s\n", s); return TextUtils.isEmpty(s); } private static void saySomething(String something) { System.out.println(something); } private String onEvent(TestEvent event) { System.out.format("Event name: %s\n", event.getEventName()); return event.getResult(); } static class TestEvent { private String eventName; private String result; public TestEvent(String eventName, String result) { this.eventName = eventName; this.result = result; } public String getResult() { return result; } public String getEventName() { return eventName; } } public static void main(String[] args) { try { Class < ?>cls = Class.forName("net.sxkeji.shixinandroiddemo2.test.reflection.MethodInvoke"); MethodInvoke object = (MethodInvoke) cls.newInstance(); Method[] declaredMethods = cls.getDeclaredMethods(); for (Method declaredMethod: declaredMethods) { String methodName = declaredMethod.getName(); //获取方法名 Type returnType = declaredMethod.getGenericReturnType(); //获取带泛型的返回值类型 int modifiers = declaredMethod.getModifiers(); //获取方法修饰符 // declaredMethod.setAccessible(true); if (methodName.equals("onEvent")) { TestEvent testEvent = new TestEvent("shixin's Event", "cuteType"); try { Object invokeResult = declaredMethod.invoke(object, testEvent); System.out.format("Invoke of %s, return %s \n", methodName, invokeResult.toString()); } catch(InvocationTargetException e) { //处理被调用方法可能抛出的异常 Throwable cause = e.getCause(); System.out.format("Invocation of %s failed: %s\n", methodName, cause.getMessage()); } } else if (returnType == boolean.class) { try { declaredMethod.invoke(object, "shixin's parameter"); } catch(InvocationTargetException e) { Throwable cause = e.getCause(); System.out.format("Invocation of %s failed: %s\n", methodName, cause.getMessage()); } } else if (Modifier.isStatic(modifiers) && !methodName.equals("main")) { //静态方法,调用时 object 直接传入 null try { declaredMethod.invoke(null, "static method"); } catch(InvocationTargetException e) { Throwable cause = e.getCause(); System.out.format("Invocation of %s failed: %s\n", methodName, cause.getMessage()); } } } } catch(ClassNotFoundException e) { e.printStackTrace(); } catch(InstantiationException e) { e.printStackTrace(); } catch(IllegalAccessException e) { e.printStackTrace(); } } }
执行结果:
checkString: shixin's parameter Invocation of checkString failed: Stub! Event name: shixin's Event Invoke of onEvent, return cuteType static method Process finished with exit code 0
总结
1. Method.invoke()本身要用数组包装参数;而且每次调用都必须检查方法的可见性(在Method.invoke()里),也必须检查每个实际参数与形式参数的类型匹配性(在NativeMethodAccessorImpl.invoke0()里或者生成的Java版MethodAccessor.invoke()里)
2. Method.invoke()就像是个独木桥一样,各处的反射调用都要挤过去,在调用点上收集到的类型信息就会很乱,影响内联程序的判断,使得Method.invoke()自身难以被内联到调用方。
版权声明:本文为JAVASCHOOL原创文章,未经本站允许不得转载。