一、场景
在一些Java框架中,程序的方法名字可以任意设计,参数可以在范围内任意出现,参数排列顺序没有要求,最后容器也能支持这些类的运行。
例如:SpringMVC的控制器,只需要用@RequestMapping注释方法,那么方法的参数可以是 HttpServletRequest、HttpServletResponse、HttpSession、String、int、Map等等类型,并且个数任意选择,顺序任意选择。
例如Tomcat调用websocket程序中,监听方法用规定的注解,方法名任意定义,参数按照规定选择,但是参数排列的顺序无要求。
二、主要思路
1、获取类的对象。
通过forName()静态方法,或者对象的getClass()或者类名.class属性获得。
类对象是java.reflect.Class类型。
2、用反射获取类的方法对象。
方法对象是java.reflect.Method类型。
3、用newInstance()方法获得类的实例。
4、根据方法对象的getParameterCount()方法获取方法的参数个数。
5、根据参数个数,定义对应个数的Object类型的数组。
Object[] arg = new Object[参数个数];
6、根据getParameters获得所有参数类型组成的数组。
数组是 Class[]类型,里面每个元素是方法参数类型的类对象,按照方法中出现的顺序在数组中从左到右排列。
例如:方法中第一个参数是int类型,那么获取的参数类型数组中第一个就是int.class类对象。
7、准备那些调用方法时使用到的所有可能出现的实例对象和变量值。
例如:JavaWeb请求每次都生成一个HttpServletRequest对象,每次HTTP请求从URL地址中获取的请求参数,用String变量存放。
8、开始给调用数组的元素按照参数类型赋值。
8.1、遍历第6步获取的Class[]类型的数组。
8.2、如果数组元素Class类型和某个类型相同,就把类型对应的对象放在Object[]类型的对应位置。
例如: 遍历发现第0号索引是int.class类型,就把预先准备的int变量存入Object[]类型的arg数组的第0号元素位置。
遍历发现下标为2的元素是HttpSession.class类型,就把HttpSession对象设置到Object[]类型数组arg的下标2号位置处。
9、调用方法对象的invoke来调用对象的方法。
invoke(生成的Object对象, 存放参数列表的Object数组)
传参:
第一个参数是Object类型,第二个是Object[]类型。
Object类型是第3步获得的实例。
Object[]是存放调用目标方法需要的实际参数的数组。
注意:传入的数组和实际需要的参数个数不相同或者类型不相同都会抛出异常。
三、通俗解释
1、反射获取类的对象和目标方法对象。
2、反射获取该方法需要的所有参数。
3、遍历参数数组。
准备一个Object类型的数组,存放调用方法的参数值。
4、调用invoke(Object, Object[])方法。
案例:
假设类MM有一个名字叫做print的方法,但是返回值和参数列表目前不知道。
通过反射发现该方法调用需要两个参数。
根据获取参数个数,定义一个元素个数为2的Object类型的数组。
遍历方法参数类型数组,发现第一个是int类型,第二个是String类型。
根据类型判断并且分别存放要调用参数值到对应位置。
假设在下标0位置处设置一个整型值100。
假设在下标1位置处设置一个字符串值 “你好”。
用invoke调用时传入生成的对象和Object类型的数组。
四、其他方法
Method的其他一些方法:
getReturnValue() 获得返回值类型。
getModifier() 获得修饰符,例如private类型。
isPrensentAnnotaion() 判断是否存在某个注解。方法如果加了某个注解,就能用该方法判断。
getAnnotaion() 获得某种类型的注解对象。
getDeclareAnnotaion() 获得定义的某种类型的注解对象。