引言
从这篇文章开始,我们讲解Method和Constructor,与之前的方式一样,我们还是先从这两个类的结构层次出发,先理解继承体系中的关键类和接口。
Method的继承体系
Method的定义如下:
public final class Method extends Executable {}
比较简单,只是继承了Executable类,再看Executable类的定义:
/**
* A shared superclass for the common functionality of {@link Method}
* and {@link Constructor}.
*
* @since 1.8
*/
public abstract class Executable extends AccessibleObject
implements Member, GenericDeclaration {}
根据注释中的解释,Executable是Method和Constructor的公共父类。我们从命名上也能大概猜到,就是可执行的意思。
Executable继承了AccessibleObject(可访问的)类,说明我们可以通过反射获取Executable(方法和构造方法)的对象,实现了Member接口,我们就可以拿到Executable(方法和构造方法)的一些标识信息,实现了GenericDeclaration接口,说明方法和构造方法是可以声明类型变量的(可以泛化的)。这三个类(接口)我们在之前的文章已经都详细的介绍过。
如果还记得Field的定义的话,会发现Executable与Field的定义很相似,都继承了AccessibleObject实现了Member,Executable比Field多实现了一个GenericDeclaration接口,因为不管是方法还是构造方法,都是可以泛化(声明类型变量)的。
因为Executable从语义上表示一个可执行的方法或构造方法,所以它会提供一些方法用来获取方法或构造方法信息如参数、参数的数量、异常等。下面我们来分析一下这些方法。
Executable的定义
Executable类的定义如下:
/**
* A shared superclass for the common functionality of {@link Method}
* and {@link Constructor}.
*
* @since 1.8
*/
public abstract class Executable extends AccessibleObject
implements Member, GenericDeclaration {}
先看注释,Executable是Method和Constructor的公共基类。它继承了AccessibleObject类,实现了Member和GenericDeclaration接口,这三个我们在前面的文章中都已经详细分析过了,这里不再赘述。继承AccessibleObject类意味着Executable(方法和构造方法)可以通过isAccessible()方法来获取是否要进行访问控制权限的校验,还可以通过setAccessible()方法来设置是否要进行访问控制权限的校验。
Executable重点方法
getParameterTypes()方法
这个方法用来获取这个Executable(方法或者构造方法)的所有的参数的类型。
public abstract Class<?>[] getParameterTypes();
getParameterCount()方法
public int getParameterCount() {
throw new AbstractMethodError();
}
getGenericParameterTypes()方法
public Type[] getGenericParameterTypes() {
if (hasGenericInformation())
return getGenericInfo().getParameterTypes();
else
return getParameterTypes();
}
这个方法返回带有泛型声明的参数。返回的是Type[]而不是Class[]。
我们看一个例子来了解这三个方法:
public class ParameterTypeTest {
public <T extends SimpleObject> void test(int i, String s, SimpleObject simpleObject,double[] doubles,T t){
System.out.println("this is a test method");
}
public static void main(String[] args) throws NoSuchMethodException {
Class<ParameterTypeTest> parameterTypeTestClass = ParameterTypeTest.class;
Method test = parameterTypeTestClass.getDeclaredMethod("test", int.class, String.class, SimpleObject.class, double[].class, SimpleObject.class);
System.out.println(test.getParameterCount());
System.out.println(Arrays.toString(test.getParameterTypes()));
System.out.println(Arrays.toString(test.getGenericParameterTypes()));
}
}
在这个例子中,我们声明了一个方法test,然后分别对这个method调用了上面的三个方法,看输出:
5
[int, class java.lang.String, class person.andy.concurrency.classload.SimpleObject, class [D, class person.andy.concurrency.classload.SimpleObject]
[int, class java.lang.String, class person.andy.concurrency.classload.SimpleObject, class [D, T]
对于最后一个带有泛型声明的参数T t,getParameterTypes方法返回的是泛型的擦除,也就是上边界SimpleObject,而getGenericParameterTypes()方法返回的是标识符T。
getExceptionTypes()方法
public abstract Class<?>[] getExceptionTypes();
这个方法返回的是方法的异常类型数组。也就是throws关键字后面声明的异常类型的数组。
getGenericExceptionTypes()方法
public Type[] getGenericExceptionTypes() {
Type[] result;
if (hasGenericInformation() &&
((result = getGenericInfo().getExceptionTypes()).length > 0))
return result;
else
return getExceptionTypes();
}
这个方法返回带有泛型声明的异常类型,返回值是type数组而不是Class数组。
下面看一个例子来理解这两个方法:
public class ParameterTypeTest {
public <T extends SimpleObject,E extends Exception> void test(T t) throws IOException,E {
System.out.println("this is a test method");
}
public static void main(String[] args) throws NoSuchMethodException {
Class<ParameterTypeTest> parameterTypeTestClass = ParameterTypeTest.class;
Method test = parameterTypeTestClass.getDeclaredMethod("test", SimpleObject.class);
Class<?>[] exceptionTypes = test.getExceptionTypes();
System.out.println(Arrays.toString(exceptionTypes));
Type[] genericExceptionTypes = test.getGenericExceptionTypes();
System.out.println(Arrays.toString(genericExceptionTypes));
}
}
输出:
[class java.io.IOException, class java.lang.Exception]
[class java.io.IOException, E]
小结
这篇文章,我们分析了Method这个类的继承关系,知道了Executable是Method和Constructor的公共父类,作为公共父类,它提供了几个方法用来获取方法或者构造方法的参数和异常信息。Method和Constructor在Executable的基础上,又各自扩展了对应的方法,这些我们会在下一篇文章讲解。