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()自身难以被内联到调用方。