Java-通过反射获取任意类的方法

一、获取方法

Class类提供了以下几个方法来获取Method

  • Method getMethod(name, Class...):获取某个public的Method(包括父类)
  • Method getDeclaredMethod(name, Class...):获取当前类的某个Method(不包括父类)
  • Method[] getMethods():获取所有public的Method(包括父类)
  • Method[] getDeclaredMethods():获取当前类的所有Method(不包括父类)

下面给出两个简单的示例:

public static <T> void getDeclaredMethods(T t) {
    Object obj = (Object) t;
    Class cls = obj.getClass();
    Method[] methods = cls.getDeclaredMethods();
    for (int i = 0; i < methods.length; i++) {
        System.out.println(methods[i]);
    }
}
public static <T> void getMethod(T t) throws NoSuchMethodException {
    Object obj = (Object) t;
    Class cls = obj.getClass();
    System.out.println(cls.getMethod("setName", String.class));
    System.out.println(cls.getMethod("getName"));
}

Field对象包含了一个字段的所有信息一样,Method对象也包含一个方法的所有信息,下面简单介绍几个常用的方法:

  • getName():返回方法名称;
  • getReturnType():返回方法返回值类型,也是一个Class实例;
  • getParameterTypes():返回方法的参数类型,是一个Class数组,例如:{String.class, int.class}

示例:

public static <T> void getMethodReturnType(T t) throws NoSuchMethodException {
    Object obj = (Object) t;
    Class cls = obj.getClass();
    Method method = cls.getMethod("setName", String.class);

    System.out.println(method.getName());    // setName
    System.out.println(method.getReturnType());    // void
    Class<?>[] p = method.getParameterTypes();
    for (int i = 0; i < p.length; i++) {
        System.out.println(p[i]);    // class java.lang.String
    }
}

下面给出一个具体的调用substring方法的示例:

public static void getSubstringMethod() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
      String str = "Happy-new-year";
      // 获取String substring(int, int)方法:
      Method m = String.class.getMethod("substring", int.class, int.class);
      // 在s对象上调用该方法并获取结果:
      String r = (String) m.invoke(str, 2,  5);
      // 打印调用结果:
      System.out.println(r);
  }

调用Method实例的invoke方法就相当于调用该方法。invoke的第一个参数是要调用的对象实例(此处substring是要对str使用,所以传入str),后续为可变参数,要与调用方法的参数保持一致。

有一些特殊的方法,情况稍有不同。

  1. 假如调用的方法为static方法,因为不需要指定调用的实例对象,所以invoke的第一个参数需设置为null

  2. 假如调用的方法为private或者protect方法。需要采取和访问私有Field的一样的方法:在使用invoke方法之前,需设置Method.setAccessible(true)

  3. 假如某一方法在父类中存在,同时在子类中也进行了重写,即存在多态的情况。使用invoke调用同样支持多态原则,会根据传入invoke方法的第一个参数的实际类型来进行调用。

上一篇:如何在Oracle中把XML转换成物理表字段的形式返回


下一篇:LC242.有效的字母异位同