Java反射–类方法

时间:2020-01-09 10:35:19  来源:igfitidea点击:

使用Java Reflection API,我们可以获得有关类方法的信息,甚至可以在运行时调用方法。在Java Reflection API中,存在一个类java.lang.reflect.Method,该类具有用于访问字段的类型,字段的修饰符以及设置和获取字段值的方法。

获取方法实例

首先要获取Method类的实例,因为我们必须使用java.lang.Class的方法,因为该类是所有反射操作的入口。

  • getMethod(String name,Class <?> ... parameterTypes)此方法返回用于类或者接口的指定公共成员方法名称的Method对象。

  • getMethods()返回一个包含方法对象的数组,该方法对象反映此Class对象表示的类或者接口的所有公共方法,包括由类或者接口声明的方法以及从超类和超接口继承的方法。

  • getDeclaredMethod(String name,Class <?>…parameterTypes)返回一个Method对象,该对象反映此类对象表示的类或者接口的指定声明方法。

  • getDeclaredMethods()返回一个数组,该数组包含反映此Class对象表示的类或者接口的所有已声明方法的Method对象,包括公共,受保护,默认(程序包)访问和私有方法,但不包括继承的方法。

  • getEnclosingMethod()如果此Class对象表示方法中的本地或者匿名类,则此方法返回一个Method对象,该对象表示基础类的立即封闭方法。

获取有关类方法的信息-Java示例

本示例说明如何使用Java Reflection API获取Method对象,并使用该方法获取有关方法类型及其修饰符的信息。在示例中使用的java.lang.reflect.Method类的方法是

  • getName()以String形式返回此Method对象表示的方法的名称。

  • getParameters()返回表示方法的所有参数的Parameter对象的数组。

  • getParameterTypes()返回表示方法参数类型的Class对象数组。

  • getReturnType()返回一个Class对象,该对象表示此Method对象表示的方法的形式返回类型。

  • getModifiers()返回方法修饰符。

对于示例,我们将使用以下类结构。

有一个接口Operation.java

public interface Operation {
	void sum(int a, int b);
}

一个充当超类的Java类。

public class Message {
  String msg;
  Message(String msg){
    this.msg = msg;
  }
  public void displayMessage(){
    System.out.println(msg);
  }
}

另一个实现Operation接口并扩展Message.java的类

public class Child extends Message implements Operation {	
  Child(String msg) {
    super(msg);
  }

  @Override
  public void sum(int a, int b) {
    System.out.println("Sum is- " + a+b);
  }

  private String prepareMessage(String msg) {
    return "Hello " + msg;
  }
}
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Arrays;

public class ReflectionDemo {
  public static void main(String[] args) {
    try {
      Child child = new Child("Java Reflection example");
      // get instance of Class
      Class<?> c = child.getClass();
        
      System.out.println("--- Using getMethod(methodName, parameters) ---");
      Method method = c.getMethod("sum", int.class, int.class);
      System.out.println("Method Name- " + method.getName());
      System.out.println("Method params- " + Arrays.toString(method.getParameters()));
      System.out.println("Method param types- " + Arrays.toString(method.getParameterTypes()));
      System.out.println("Method Returns- " + method.getReturnType());
      int mod = method.getModifiers();
      System.out.println("Method modifiers - " + Modifier.toString(mod));
      
      System.out.println("--- Using getDeclaredMethod(methodName, parameters) ---");
      System.out.println("Method Name- " + method.getName());
      method = c.getDeclaredMethod("prepareMessage", String.class);
      System.out.println("Method params- " + Arrays.toString(method.getParameters()));
      
      System.out.println("--- Using getMethods() ---");
      Method[] methods = c.getMethods();
      System.out.println("All Methods " + Arrays.toString(methods));
      
      System.out.println("--- Using getDeclaredMethods() ---");       
      methods = c.getDeclaredMethods();
        for(Method m: methods) {
          System.out.println("Method Name- " + m.getName());
          System.out.println("Method Parameters- " + Arrays.toString(m.getParameters()));
        }
        
    } catch (NoSuchMethodException | SecurityException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
  }
}

输出:

--- Using getMethod(methodName, parameters) --
Method Name- sum
Method params- [int arg0, int arg1]
Method param types- [int, int]
Method Returns- void
Method modifiers - public
--- Using getDeclaredMethod(methodName, parameters) --
Method Name- sum
Method params- [java.lang.String arg0]
--- Using getMethods() --
All Methods [public void com.theitroad.programs.Child.sum(int,int), public void com.theitroad.programs.Message.displayMessage(), public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException, public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException, public final void java.lang.Object.wait() throws java.lang.InterruptedException, public boolean java.lang.Object.equals(java.lang.Object), public java.lang.String java.lang.Object.toString(), public native int java.lang.Object.hashCode(), public final native java.lang.Class java.lang.Object.getClass(), public final native void java.lang.Object.notify(), public final native void java.lang.Object.notifyAll()]
--- Using getDeclaredMethods() --
Method Name- sum
Method Parameters- [int arg0, int arg1]
Method Name- prepareMessage
Method Parameters- [java.lang.String arg0]

从该示例中观察到的几件事是

  • 使用getDeclaredMethod()还可以获取有关该类的私有方法的信息。

  • GetMethods()返回该类以及超类的所有方法。

  • GetDeclaredMethods()返回该类的所有方法,包括私有方法和受保护方法。

使用Java Reflection调用类方法

我们可以在运行时使用Reflection API调用类的方法。在Method类中,有用于此目的的invoke(Object obj,Object…args)。

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class ReflectionDemo {
  public static void main(String[] args) {
    try {
      Child child = new Child("Java Reflection example");
      // get instance of Class
      Class<?> c = child.getClass();
      Method method = c.getMethod("sum", int.class, int.class);
      // Invoking method
      method.invoke(child, 5, 6);
    } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException | IllegalArgumentException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
  }
}

使用Java Reflection调用私有方法

我们甚至可以使用Java Refelction API调用该类的私有方法。

一旦有了方法对象,就必须使用setAccessible()方法将私有方法的访问权限设置为true,该方法是从类java.lang.reflect.AccessibleObject继承的,然后调用该方法。

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class ReflectionDemo {
  public static void main(String[] args) {
    try {
      Child child = new Child("Java Reflection example");
        // get instance of Class
        Class<?> c = child.getClass();
        Method method = c.getDeclaredMethod("prepareMessage", String.class);
        method.setAccessible(true);
        // Invoking method
        String message = (String)method.invoke(child, "Java Reflection API");
        System.out.println("Message- " + message);
    } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException | IllegalArgumentException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
  }
}

输出:

Message- Hello Java Reflection API