Java 高级教程系列 - 方法反射

Java Tutorial for Language Adavanced - Method Reflection

Posted by zihengCat on 2019-03-25

方法反射(Method Reflection)

Java 类java.lang.reflect.Method实例是对类方法(Method)的反射。Method类继承自通用抽象父类Executable,其自身是不可变(Immutable)类。

Method[] getMethods()
Method[] getDeclaredMethods()
Method getMethod(String name, Class<?>... parameterTypes)
Method getDeclaredMethod(String name, Class<?>... parameterTypes)

代码清单:方法(Method)信息反射 API

方法 描述
Method[] getMethods() 返回目标类中所有可访问的公开方法,包括从父类继承的公开方法。
Method[] getDeclaredMethods() 返回目标类中所有方法,不包括从父类继承的方法。
Method getMethod(String name, Class... parameterTypes) 根据方法名与参数类型取得目标方法对象。
Method getDeclaredMethod(String name, Class... parameterTypes) 根据方法名与参数类型取得目标方法对象,不包括从父类继承的方法。

表:方法(Method)反射 API 表

getMethods()返回类中所有公开方法(public),包括从父类继承的公开方法,返回值为方法对象数组Method[]

getDeclaredMethods()方法返回类中所有方法(publicprivateprotected),但不包括从父类继承的方法,返回值为方法对象数组Method[]

getMethod(String name, Class<?>... parameterTypes)getDeclaredMethod(String name, Class<?>... parameterTypes)根据方法名参数类型取得目标方法对象Method,如果目标字段不存在,则抛出NoSuchMethodException异常。

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Parameter;
public class Main {
    public static void main(String[] args) {
        for (Method m : TestClass.class.getDeclaredMethods()) {
            System.out.printf(
                /*
                 * Modifier
                 * ReturnType MethodName(
                 *     ParameterType arg0, ParameterType arg1, ...
                 * )
                 * throws Exception
                 */
                "%s %s %s(%s) %s\n",
                Modifier.toString(m.getModifiers()),
                m.getReturnType().getSimpleName(),
                m.getName(),
                getParameterString(m),
                getExceptionString(m).equals("") ?
                getExceptionString(m) : "throws " + getExceptionString(m)
            );
        }
    }
    public static String getExceptionString(Method m) {
        StringBuilder sb = new StringBuilder();
        for (Class<?> c : m.getExceptionTypes()) {
            sb.append(c.getSimpleName());
            sb.append(", ");
        }
        return sb.toString();
    }
    public static String getParameterString(Method m) {
        StringBuilder sb = new StringBuilder();
        for (Parameter p : m.getParameters()) {
            sb.append(
                p.getType().getSimpleName()
            );
            sb.append(" ");
            sb.append(
                p.getName()
            );
            sb.append(", ");
        }
        return sb.toString();
    }
}
class TestSuperClass {
    public TestSuperClass() {
        // ...
    }
    public void sayHello() {
        System.out.println("Hello!");
    }
}
class TestClass<T> extends TestSuperClass {
    public TestClass() {
        // ...
    }
    public TestClass(T t) {
        // ...
    }
    public static Integer getInt(String s) throws Exception {
        return Integer.valueOf(s);
    }
    public static Integer getInt(Integer i) throws Exception {
        return i;
    }
}

代码清单:反射获取方法(Method)信息

反射调用方法

对于方法(Method)反射,我们主要关心如何通过反射调用目标方法,Method类提供了invoke(Object obj, Object... args)方法,允许我们通过反射调用方法。

Method.invoke(Object obj, Object... args)方法第一个参数是一个类实例,第二个参数是目标方法的参数列表,如果第一个参数为null,则表示调用类静态方法。

public Object invoke(Object obj, Object... args)
throws IllegalAccessException,
       IllegalArgumentException,
       InvocationTargetException

代码清单:invoke方法声明

...
    public static void main(String[] args) {
        try {
            TestClass t = new TestClass();
            Method m = TestClass.class.getDeclaredMethod(
                "getInt", String.class
            );
            System.out.println(
                m.invoke(t, "123")
            );
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
...

代码清单:invoke反射调用方法

参考资料