我们已经通过Class实例获取所有Filed对象,同样的,可以通过class实例获取所有Method信息。

  • Method getMethod(name,Class..):获取某个publicMethod(包括父类)
  • Method[] getMethods()获取所有publicMethod(包括父类)
  • Method getDeclaredMethod(name, Class..)获取当前类的某个Method(不包括父类)
  • Method[] getDeclaredMethods(name, Class..)获取当前类的所有Method(不包括父类) ```java public class Main { public static void main(String[] args){
    1. Class studentClass = Student.class;
    2. // 获取public方法getScore,参数为String:
    3. System.out.println(studentClass.getDeclaredMethod("getScore",String.class));
    4. // 获取继承的public方法getName,无参数:
    5. System.out.println(studentClass.getMethod("getName"));
    6. // 获取private方法getGrade,参数为int:
    7. System.out.println(studentClass.getDeclaredMethod("getGrade",int.class));
    } }

class Student extends Person { public int getScore(String type){ return 99; }

private int getGrade(int year){
    return 1;
}

}

class Person { public String getName(){ return “Person”; } }

打印出的结果类似
```java
public int LearnClass.Student.getScore(java.lang.String)
public java.lang.String LearnClass.Person.getName()
public int LearnClass.Student.getGrade(int)

一个Method对象包含一个方法的所有信息

  • getName() 返回方法名称,例如"getScore"
  • getReturnType() 返回方法返回值类型,也是一个Class实例,例如String.class
  • getParameterTypes() 返回方法的参数类型,是一个Class数组,例如:{String.class,int.class}
  • getModifiers() 返回方法的修饰符,它是一个int,不同的bit表示不同的含义。

    调用方法

    当我们获取到一个Method对象时,就可以对它进行调用。例如

    String s = "Hello world";
    String r = s.substring(6);//"world"
    

    如果用反射来调用substring方法,需要以下代码

    public class Main {
      public static void main(String[] args){
          String s = "Hello world";
          Method m = String.class.getMethod("substring",int.class);
          String r = (string) m.invoke(s,6);
          System.out.println(r);
      }
    }
    

    注意到substring()有两个重载方法,我们获取的是String substring(int)这个方法。思考一下如何获取String substring(int,int)方法。
    Method实例调用invoke就相当于调用该方法,invoke的第一个参数是对象实例,即在哪个实例上调用该方法,后面的可变参数要与方法参数一致,否则将报错。

    调用静态方法

    如果获取到的Method表示一个静态方法,调用静态方法时,由于无需指定实例对象,所以invoke方法传入的第一个参数永远为null。我们以Integer.pareseInt(String)为例

    public class Main {
      public static void main(String args) {
        Method m = Integer.class.getMethod("parseInt",String.class);
      Integer n = (Integer) m.invoke(null,"2322");
      System.out.println(n);
    }
    }
    

    调用非public方法

    和Field类似,对于非public方法,我们虽然可以通过Class.getDeclaredMethod()获取该方法实例,但直接对其调用将得到一个IllegalAccessException。为了调用非public方法,我们通过Method.setAccessible(true)允许其调用

    public class Main {
      public static void main(String[] args){
        Person p = new Person();
      Method m = p.getClass().getDeclaredMethod("setName",String.class);
      m.invoke(p,"bob");
      System.out.println(p.name);
    }
    }
    class Person{
      String name;
    private void setName(String name){
        this.name = name;
    }
    }
    

    同样,setAccessible(true)可能会失败。如果JVM运行期存在SecureityManager,那么它会根据规则进行检查,有可能阻止setAccessible(true)。例如,某个SecurityManager可能不允许对javajavax开头的package的类调用setAccessible(true),这样可以保证JVM核心库的安全。

    多态

    我们来考察这样一种情况:一个Person类定义 了hello()方法,并且他的子类Student也覆写了hello()方法,那么,从Person.class获取的Method,作用于Student实例时,调用的方法到底是哪个? ```java public class Main{ public static void main(Strig[] args){

    Method m = Person.class.getMethod("sayHello");
    

    Person p = new Student(); m.invoke(p);

    } }

class Student extends Person {

@ovirride

public void sayHello(){ System.out.println(“Student: hello!”); } }

class Person {

public void sayHello(){
  System.out.println("Person: hello");

} }

运行上述代码,发现打印出的是`Student: hello`,因此,使用反射调用方法时,仍然遵循多态原则:即总是调用实际类型的覆写方法(如果存在)上述反射代码
```java
Method m = Person.class.getMethod("sayHello");
Person p = new Student();
m.invoke(p);

实际上相当于

m.invoke(new Student());

小结:

  • Java的反射API提供的Method对象封装了方法的所有信息
  • 通过Class实例的方法可以获取Method实例:getMethod()getMethods()getDeclaredMethod() ,getDeclaredMethods()
  • 通过Method实例可以获取方法信息getName()getReturnType()getParameterTypes()getModifires()
  • 通过Method实例可以调用某个对象的方法:Object invoke(Object instance,Object... parameters)
  • 通过设置setAccessible(true)来访问非public方法
  • 通过反射调用方法时, 仍然遵循多态原则。