引言

从这篇文章开始,我们讲解Method和Constructor,与之前的方式一样,我们还是先从这两个类的结构层次出发,先理解继承体系中的关键类和接口。

Method的继承体系

Method的定义如下:

  1. public final class Method extends Executable {}

比较简单,只是继承了Executable类,再看Executable类的定义:

  1. /**
  2. * A shared superclass for the common functionality of {@link Method}
  3. * and {@link Constructor}.
  4. *
  5. * @since 1.8
  6. */
  7. public abstract class Executable extends AccessibleObject
  8. implements Member, GenericDeclaration {}

根据注释中的解释,Executable是Method和Constructor的公共父类。我们从命名上也能大概猜到,就是可执行的意思。
Executable继承了AccessibleObject(可访问的)类,说明我们可以通过反射获取Executable(方法和构造方法)的对象,实现了Member接口,我们就可以拿到Executable(方法和构造方法)的一些标识信息,实现了GenericDeclaration接口,说明方法和构造方法是可以声明类型变量的(可以泛化的)。这三个类(接口)我们在之前的文章已经都详细的介绍过。
methodInherit.png
如果还记得Field的定义的话,会发现Executable与Field的定义很相似,都继承了AccessibleObject实现了Member,Executable比Field多实现了一个GenericDeclaration接口,因为不管是方法还是构造方法,都是可以泛化(声明类型变量)的。
因为Executable从语义上表示一个可执行的方法或构造方法,所以它会提供一些方法用来获取方法或构造方法信息如参数、参数的数量、异常等。下面我们来分析一下这些方法。

Executable的定义

Executable类的定义如下:

  1. /**
  2. * A shared superclass for the common functionality of {@link Method}
  3. * and {@link Constructor}.
  4. *
  5. * @since 1.8
  6. */
  7. public abstract class Executable extends AccessibleObject
  8. implements Member, GenericDeclaration {}

先看注释,Executable是Method和Constructor的公共基类。它继承了AccessibleObject类,实现了Member和GenericDeclaration接口,这三个我们在前面的文章中都已经详细分析过了,这里不再赘述。继承AccessibleObject类意味着Executable(方法和构造方法)可以通过isAccessible()方法来获取是否要进行访问控制权限的校验,还可以通过setAccessible()方法来设置是否要进行访问控制权限的校验。

Executable重点方法

getParameterTypes()方法

这个方法用来获取这个Executable(方法或者构造方法)的所有的参数的类型。

  1. public abstract Class<?>[] getParameterTypes();

注意返回值是Class数组。

getParameterCount()方法

  1. public int getParameterCount() {
  2. throw new AbstractMethodError();
  3. }

这个方法返回方法的参数的个数。

getGenericParameterTypes()方法

  1. public Type[] getGenericParameterTypes() {
  2. if (hasGenericInformation())
  3. return getGenericInfo().getParameterTypes();
  4. else
  5. return getParameterTypes();
  6. }

这个方法返回带有泛型声明的参数。返回的是Type[]而不是Class[]。
我们看一个例子来了解这三个方法:

  1. public class ParameterTypeTest {
  2. public <T extends SimpleObject> void test(int i, String s, SimpleObject simpleObject,double[] doubles,T t){
  3. System.out.println("this is a test method");
  4. }
  5. public static void main(String[] args) throws NoSuchMethodException {
  6. Class<ParameterTypeTest> parameterTypeTestClass = ParameterTypeTest.class;
  7. Method test = parameterTypeTestClass.getDeclaredMethod("test", int.class, String.class, SimpleObject.class, double[].class, SimpleObject.class);
  8. System.out.println(test.getParameterCount());
  9. System.out.println(Arrays.toString(test.getParameterTypes()));
  10. System.out.println(Arrays.toString(test.getGenericParameterTypes()));
  11. }
  12. }

在这个例子中,我们声明了一个方法test,然后分别对这个method调用了上面的三个方法,看输出:

  1. 5
  2. [int, class java.lang.String, class person.andy.concurrency.classload.SimpleObject, class [D, class person.andy.concurrency.classload.SimpleObject]
  3. [int, class java.lang.String, class person.andy.concurrency.classload.SimpleObject, class [D, T]

对于最后一个带有泛型声明的参数T t,getParameterTypes方法返回的是泛型的擦除,也就是上边界SimpleObject,而getGenericParameterTypes()方法返回的是标识符T。

getExceptionTypes()方法

  1. public abstract Class<?>[] getExceptionTypes();

这个方法返回的是方法的异常类型数组。也就是throws关键字后面声明的异常类型的数组。

getGenericExceptionTypes()方法

  1. public Type[] getGenericExceptionTypes() {
  2. Type[] result;
  3. if (hasGenericInformation() &&
  4. ((result = getGenericInfo().getExceptionTypes()).length > 0))
  5. return result;
  6. else
  7. return getExceptionTypes();
  8. }

这个方法返回带有泛型声明的异常类型,返回值是type数组而不是Class数组。
下面看一个例子来理解这两个方法:

  1. public class ParameterTypeTest {
  2. public <T extends SimpleObject,E extends Exception> void test(T t) throws IOException,E {
  3. System.out.println("this is a test method");
  4. }
  5. public static void main(String[] args) throws NoSuchMethodException {
  6. Class<ParameterTypeTest> parameterTypeTestClass = ParameterTypeTest.class;
  7. Method test = parameterTypeTestClass.getDeclaredMethod("test", SimpleObject.class);
  8. Class<?>[] exceptionTypes = test.getExceptionTypes();
  9. System.out.println(Arrays.toString(exceptionTypes));
  10. Type[] genericExceptionTypes = test.getGenericExceptionTypes();
  11. System.out.println(Arrays.toString(genericExceptionTypes));
  12. }
  13. }

输出:

  1. [class java.io.IOException, class java.lang.Exception]
  2. [class java.io.IOException, E]

与获取参数的思路是类似的,这里不再赘述。

小结

这篇文章,我们分析了Method这个类的继承关系,知道了Executable是Method和Constructor的公共父类,作为公共父类,它提供了几个方法用来获取方法或者构造方法的参数和异常信息。Method和Constructor在Executable的基础上,又各自扩展了对应的方法,这些我们会在下一篇文章讲解。