Java反射类java.lang.reflect.Method类介绍

x33g5p2x  于2021-08-20 转载在 Java  
字(9.2k)|赞(0)|评价(0)|浏览(463)

1. 概述

java.lang.reflect.Method类提供了访问Method的修饰符、返回类型、参数、注解和抛出异常信息的API。它也被用来调用Methods。
下面的类图显示java.lang.reflect.Method类提供了访问Method的修饰符、返回类型、参数、注释和抛出的异常信息的API。

2. 反射Method API示例

*获取Method类型信息

  • 获取Method参数的名称
  • 检索和解析Method修改器
  • 获得公共Method
  • 调用公共Method
  • 获取所有公共Method
    在本指南中,我们将研究类的上述所有重要Methods。

2.1 获取Method类型信息

这个例子说明了如何在一个给定的类中枚举所有声明的Method,并检索给定名称的所有Method的返回、参数和异常类型。

public static void reflectionMethodExamples() {
 final String fmt = "%24s: %s%n";
 try {
     Class<?> c = Class.forName("com.javaguides.reflection.methods.Employee");
     Method[] allMethods = c.getDeclaredMethods();
     for (Method m : allMethods) {
         out.format("%s%n", m.toGenericString());

         out.format(fmt, "ReturnType", m.getReturnType());
         out.format(fmt, "GenericReturnType", m.getGenericReturnType());

         Class<?>[] pType = m.getParameterTypes();
         Type[] gpType = m.getGenericParameterTypes();
         for (int i = 0; i < pType.length; i++) {
             out.format(fmt, "ParameterType", pType[i]);
             out.format(fmt, "GenericParameterType", gpType[i]);
         }

         Class<?>[] xType = m.getExceptionTypes();
         Type[] gxType = m.getGenericExceptionTypes();
         for (int i = 0; i < xType.length; i++) {
             out.format(fmt, "ExceptionType", xType[i]);
             out.format(fmt, "GenericExceptionType", gxType[i]);
         }
     }
     // production code should handle these exceptions more gracefully
    } catch (ClassNotFoundException x) {
        x.printStackTrace();
    }
}

输出:

public java.lang.String com.javaguides.reflection.methods.Employee.getName()
              ReturnType: class java.lang.String
       GenericReturnType: class java.lang.String
public int com.javaguides.reflection.methods.Employee.getId()
              ReturnType: int
       GenericReturnType: int
public void com.javaguides.reflection.methods.Employee.setName(java.lang.String)
              ReturnType: void
       GenericReturnType: void
           ParameterType: class java.lang.String
    GenericParameterType: class java.lang.String
private int com.javaguides.reflection.methods.Employee.getAge()
              ReturnType: int
       GenericReturnType: int
public void com.javaguides.reflection.methods.Employee.setId(int)
              ReturnType: void
       GenericReturnType: void
           ParameterType: int
    GenericParameterType: int

2.2 获取Method参数的名称

MethodParameterSpy例子说明了如何检索一个给定类的所有构造函数和Methods的形式参数的名称。这个例子还打印了关于每个参数的其他信息。

package com.javaguides.reflection.methods;

import static java.lang.System.out;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
 
public class MethodParameterSpy {
     
    private static final String  fmt = "%24s: %s%n";
 
    // for the morbidly curious
    <E extends RuntimeException> void genericThrow() throws E {}
     
    public static void printClassConstructors(Class c) {
        Constructor[] allConstructors = c.getConstructors();
        out.format(fmt, "Number of constructors", allConstructors.length);
        for (Constructor currentConstructor : allConstructors) {
            printConstructor(currentConstructor);
        }  
        Constructor[] allDeclConst = c.getDeclaredConstructors();
        out.format(fmt, "Number of declared constructors",
            allDeclConst.length);
        for (Constructor currentDeclConst : allDeclConst) {
            printConstructor(currentDeclConst);
        }          
    }
     
    public static void printClassMethods(Class c) {
       Method[] allMethods = c.getDeclaredMethods();
        out.format(fmt, "Number of methods", allMethods.length);
        for (Method m : allMethods) {
            printMethod(m);
        }        
    }
     
    public static void printConstructor(Constructor c) {
        out.format("%s%n", c.toGenericString());
        Parameter[] params = c.getParameters();
        out.format(fmt, "Number of parameters", params.length);
        for (int i = 0; i < params.length; i++) {
            printParameter(params[i]);
        }
    }
     
    public static void printMethod(Method m) {
        out.format("%s%n", m.toGenericString());
        out.format(fmt, "Return type", m.getReturnType());
        out.format(fmt, "Generic return type", m.getGenericReturnType());
                 
        Parameter[] params = m.getParameters();
        for (int i = 0; i < params.length; i++) {
            printParameter(params[i]);
        }
    }
     
    public static void printParameter(Parameter p) {
        out.format(fmt, "Parameter class", p.getType());
        out.format(fmt, "Parameter name", p.getName());
        out.format(fmt, "Modifiers", p.getModifiers());
        out.format(fmt, "Is implicit?", p.isImplicit());
        out.format(fmt, "Is name present?", p.isNamePresent());
        out.format(fmt, "Is synthetic?", p.isSynthetic());
    }
     
    public static void main(String... args) {        
 
        try {
            printClassConstructors(Class.forName("com.javaguides.reflection.methods.Employee"));
            printClassMethods(Class.forName("com.javaguides.reflection.methods.Employee"));
        } catch (ClassNotFoundException x) {
            x.printStackTrace();
        }
    }
}

输出:

Number of constructors: 1
public com.javaguides.reflection.methods.Employee()
    Number of parameters: 0
Number of declared constructors: 1
public com.javaguides.reflection.methods.Employee()
    Number of parameters: 0
       Number of methods: 5
public java.lang.String com.javaguides.reflection.methods.Employee.getName()
             Return type: class java.lang.String
     Generic return type: class java.lang.String
public int com.javaguides.reflection.methods.Employee.getId()
             Return type: int
     Generic return type: int
public void com.javaguides.reflection.methods.Employee.setName(java.lang.String)
             Return type: void
     Generic return type: void
         Parameter class: class java.lang.String
          Parameter name: arg0
               Modifiers: 0
            Is implicit?: false
        Is name present?: false
           Is synthetic?: false
public void com.javaguides.reflection.methods.Employee.setId(int)
             Return type: void
     Generic return type: void
         Parameter class: int
          Parameter name: arg0
               Modifiers: 0
            Is implicit?: false
        Is name present?: false
           Is synthetic?: false
private int com.javaguides.reflection.methods.Employee.getAge()
             Return type: int
     Generic return type: int

2.3 检索和解析Method修饰符

有几个修饰符可能是Method声明的一部分。

  • 访问修饰符:public, protected, and private
  • 限制一个实例的修饰符:static
  • 禁止修改值的修饰符:final
  • 要求覆盖的修饰符:Abstract
  • 防止重入的修饰语:synchronized
  • 表示用另一种编程语言实现的修饰符:native
  • 强制执行严格的浮点行为的修饰符:strictfp
    *注解
    MethodModifierSpy例子列出了具有给定名称的Method的修改器。它还显示该Method是合成的(编译器生成的)、可变节数的,还是桥接的Method(编译器生成的以支持通用接口)。
package com.javaguides.reflection.methods;

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import static java.lang.System.out;

public class MethodModifierSpy {

    private static int count;

    private static synchronized void inc() {
       count++;
    }

    private static synchronized int cnt() {
        return count;
    }

    public static void main(String... args) {
     try {
         Class<?> c = Class.forName("java.lang.Object");
         Method[] allMethods = c.getDeclaredMethods();
         for (Method m : allMethods) {
           if (!m.getName().equals("wait")) {
              continue;
           }
           out.format("%s%n", m.toGenericString());
           out.format("  Modifiers:  %s%n", Modifier.toString(m.getModifiers()));
           out.format("  [ synthetic=%-5b var_args=%-5b bridge=%-5b ]%n", m.isSynthetic(), m.isVarArgs(),
           m.isBridge());
           inc();
         }
         out.format("%d matching overload%s found%n", cnt(), (cnt() == 1 ? "" : "s"));

         // production code should handle this exception more gracefully
       } catch (ClassNotFoundException x) {
            x.printStackTrace();
       }
    }
}

输出:

public final void java.lang.Object.wait() throws java.lang.InterruptedException
  Modifiers:  public final
  [ synthetic=false var_args=false bridge=false ]
public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
  Modifiers:  public final
  [ synthetic=false var_args=false bridge=false ]
public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
  Modifiers:  public final native
  [ synthetic=false var_args=false bridge=false ]
3 matching overloads found

让我们首先创建Employee.java类,然后我们将在Employee类上应用所有的反射API Methods。

Employee.java

package com.javaguides.reflection.methods;

public class Employee {
 
    private int id;
    private String name;
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}

2.4 获取公共Method

我们可以使用getMethod()来获取一个类的公共Method,我们需要传递Method名称和Method的参数类型。如果在类中没有找到该Method,反射API会在超类中寻找该Method。

Class<?> concreteClass = Class.forName("com.javaguides.reflection.methods.Employee");
Method method = concreteClass.getMethod("getName");
System.out.println(method.getName());

Method method2 = concreteClass.getMethod("getId", String.class);
System.out.println(method2.getName());

Method putMethod = Class.forName("java.util.HashMap").getMethod("put", Object.class, Object.class);
// get method parameter types, prints "[class java.lang.Object, class
// java.lang.Object]"
System.out.println(Arrays.toString(putMethod.getParameterTypes()));
// get method return type, return "class java.lang.Object", class
// reference for void
System.out.println(putMethod.getReturnType());
// get method modifiers
System.out.println(Modifier.toString(method.getModifiers()));

输出:

getName
setId
[class java.lang.Object, class java.lang.Object]
class java.lang.Object
public

2.5 调用公共Method

我们可以使用Method对象的invoke()Method来调用一个Method,在下面的示例代码中,我们使用反射来调用HashMap上的putMethod。

Method method = Class.forName("java.util.HashMap").getMethod("put", Object.class, Object.class);
Map<String, String> hm = new HashMap<>();
method.invoke(hm, "key", "value");
System.out.println(hm); // prints {key=value}

2.6 获取所有公共Methods

getMethods() Method 返回该类的公共Methods数组,包括它的超类和超接口的公共Methods。

Class<?> concreteClass = Class.forName("com.javaguides.reflection.methods.Employee");
Method[] methods = concreteClass.getMethods();
for (Method method : methods) {
    System.out.println(method.getName());
}

输出:

getName
getId
setName
setId
wait
wait
wait
equals
toString
hashCode
getClass
notify
notifyAll

3. 参考资料

https://docs.oracle.com/javase/tutorial/reflect/class/index.html

https://docs.oracle.com/javase/8/docs/api/java/lang/reflect/package-summary.html
https://docs.oracle.com/javase/8/docs/api/java/lang/reflect/Method.html

相关文章