文档

Java™ 教程
隐藏目录
获取方法类型信息
路径: 反射API
课程: 成员
章节: 方法

获取方法类型信息

方法声明包括名称、修饰符、参数、返回类型和可抛出异常的列表。 java.lang.reflect.Method 类提供了一种获取这些信息的方式。

示例 MethodSpy 演示了如何枚举给定类中的所有已声明方法,并检索给定名称的所有方法的返回类型、参数类型和异常类型。

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

public class MethodSpy {
    private static final String  fmt = "%24s: %s%n";

    // for the morbidly curious
    <E extends RuntimeException> void genericThrow() throws E {}

    public static void main(String... args) {
	try {
	    Class<?> c = Class.forName(args[0]);
	    Method[] allMethods = c.getDeclaredMethods();
	    for (Method m : allMethods) {
		if (!m.getName().equals(args[1])) {
		    continue;
		}
		out.format("%s%n", m.toGenericString());

		out.format(fmt, "返回类型", m.getReturnType());
		out.format(fmt, "泛型返回类型", m.getGenericReturnType());

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

		Class<?>[] xType  = m.getExceptionTypes();
		Type[] gxType = m.getGenericExceptionTypes();
		for (int i = 0; i < xType.length; i++) {
		    out.format(fmt,"异常类型", xType[i]);
		    out.format(fmt,"泛型异常类型", gxType[i]);
		}
	    }

        // 产品代码应该更优雅地处理这些异常
	} catch (ClassNotFoundException x) {
	    x.printStackTrace();
	}
    }
}

这是 Class.getConstructor() 的输出示例,它是一个具有参数化类型和可变数量参数的方法。

$ java MethodSpy java.lang.Class getConstructor
public java.lang.reflect.Constructor<T> java.lang.Class.getConstructor
  (java.lang.Class<?>[]) throws java.lang.NoSuchMethodException,
  java.lang.SecurityException
              返回类型: class java.lang.reflect.Constructor
       泛型返回类型: java.lang.reflect.Constructor<T>
           参数类型: class [Ljava.lang.Class;
    泛型参数类型: java.lang.Class<?>[]
           异常类型: class java.lang.NoSuchMethodException
    泛型异常类型: class java.lang.NoSuchMethodException
           异常类型: class java.lang.SecurityException
    泛型异常类型: class java.lang.SecurityException

这是源代码中方法的实际声明:

public Constructor<T> getConstructor(Class<?>... parameterTypes)

首先要注意返回类型和参数类型都是泛型的。如果类文件中存在 Signature 属性,Method.getGenericReturnType() 将会查找该属性。如果属性不可用,它将回退到 Method.getReturnType(),这个方法在引入泛型之前没有改变。反射中的其他以 "getGenericFoo()" 命名的方法也是类似实现。

接下来,注意最后(也是唯一的)一个参数 parameterType 是可变参数(具有可变数量的参数),类型为 java.lang.Class。它被表示为类型为 java.lang.Class 的单维数组。可以通过调用 Method.isVarArgs() 来区分它与明确声明为 java.lang.Class 数组的参数。Method.get*Types() 返回值的语法在 Class.getName() 中有描述。

以下示例演示了一个具有泛型返回类型的方法。

$ java MethodSpy java.lang.Class cast
public T java.lang.Class.cast(java.lang.Object)
              ReturnType: class java.lang.Object
       GenericReturnType: T
           ParameterType: class java.lang.Object
    GenericParameterType: class java.lang.Object

方法 Class.cast() 的泛型返回类型报告为 java.lang.Object,因为泛型是通过类型擦除来实现的,在编译过程中移除了所有关于泛型类型的信息。对于 T 的擦除由 Class 的声明来定义:

public final class Class<T> implements ...

因此,T 被替换为类型变量的上界,在这种情况下是 java.lang.Object

最后一个示例说明了具有多个重载的方法的输出。

$ java MethodSpy java.io.PrintStream format
public java.io.PrintStream java.io.PrintStream.format
  (java.util.Locale,java.lang.String,java.lang.Object[])
              ReturnType: class java.io.PrintStream
       GenericReturnType: class java.io.PrintStream
           ParameterType: class java.util.Locale
    GenericParameterType: class java.util.Locale
           ParameterType: class java.lang.String
    GenericParameterType: class java.lang.String
           ParameterType: class [Ljava.lang.Object;
    GenericParameterType: class [Ljava.lang.Object;
public java.io.PrintStream java.io.PrintStream.format
  (java.lang.String,java.lang.Object[])
              ReturnType: class java.io.PrintStream
       GenericReturnType: class java.io.PrintStream
           ParameterType: class java.lang.String
    GenericParameterType: class java.lang.String
           ParameterType: class [Ljava.lang.Object;
    GenericParameterType: class [Ljava.lang.Object;

如果发现同一方法名的多个重载方法,它们都将被 Class.getDeclaredMethods() 返回。由于 format() 有两个重载方法(一个带有 Locale,一个没有),所以 MethodSpy 显示了两个方法。


注意: Method.getGenericExceptionTypes() 存在的原因是因为实际上可以声明具有通用异常类型的方法。然而,这很少使用,因为无法捕获通用异常类型。

上一页: 方法
下一页: 获取方法参数的名称