Java教程是针对JDK 8编写的。本页面中描述的示例和实践不利用后续版本中引入的改进,并可能使用不再可用的技术。
请参阅Java语言更改以获取Java SE 9及后续版本中更新的语言特性摘要。
请参阅JDK发布说明以获取有关所有JDK版本的新功能、增强功能和已删除或弃用选项的信息。
方法声明包括名称、修饰符、参数、返回类型和可抛出异常的列表。 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
显示了两个方法。