1、获取方法
使用反射获取某一个类中的方法,步骤:
①找到获取方法所在类的字节码对象
②找到需要被获取的方法

Class类中常用方法:

public Method[] getMethods():获取包括自身和继承过来的所有的public方法
public Method[] getDeclaredMethods():获取自身所有的方法(不包括继承的,和访问权限无关)
public Method getMethod(String methodName,Class<?>...parameterTypes):
表示调用指定的一个公共的方法(包括继承的)
参数:
methodName: 表示被调用方法的名字
parameterTypes:表示被调用方法的参数的Class类型如String.class
只有通过方法签名才能找到唯一的方法,方法签名=方法名+参数列表(参数类型、参数个数、参数顺序)。
public Method getDeclaredMethod(String name, Class<?>... parameterTypes):表示调用指定的一个本类中的方法(不包括继承的)
参数:
methodName: 表示被调用方法的名字
parameterTypes:表示被调用方法的参数的Class类型如String.class

总结:
四个方法中,不带Declared的方法能获取自身类和父类的所有public方法。带Declared的方法能获取自身所有方法但不能获取父类中的方法。
只有通过方法签名才能找到唯一的方法,方法签名=方法名+参数列表(参数类型、参数个数、参数顺序)。
只能获取父类中的public方法,无法获取到父类的默认权限和private权限方法。

测试代码如下:

class P{

public void t1(){}
void t2(){}
private void t3(){}
}
class People extends P{
public void sayHi() {
System.out.println("sayHi()");
} public void sayHello(String name) {
System.out.println("sayHello(String name) " + "name = " + name);
} private void sayGoodBye(String name, int age) {
System.out.println("sayGoodBye(String name, int age) " + "name = " + name + " age = " + age);
}
}
public class MethodDemo {
public static void main(String[] args) throws Exception {
Class clazz = People.class;
//获取类自身及父类所有public方法
Method ms[] = clazz.getMethods();
for (Method m : ms) {
System.out.println(m);
}
System.out.println("---------------------------"); //获取类自身所有方法(不会获取父类方法)
ms = clazz.getDeclaredMethods();
for (Method m : ms) {
System.out.println(m);
}
System.out.println("---------------------------"); //只能获取父类中的public方法,无法获取到父类的默认权限和private权限方法
Method m = clazz.getMethod("t1", null);//public void com.reflex.P.t1()
System.out.println(m);
// m = clazz.getMethod("t2", null);//Exception in thread "main" java.lang.NoSuchMethodException: com.reflex.People.t2()
// m = clazz.getMethod("t3", null);//Exception in thread "main" java.lang.NoSuchMethodException: com.reflex.People.t3()
m = clazz.getMethod("sayHello", String.class);
System.out.println(m);
//Exception in thread "main" java.lang.NoSuchMethodException: com.reflex.People.sayGoodBye(java.lang.String, int) //getMethod方法只能获取public的
// m = clazz.getMethod("sayGoodBye", String.class,int.class);
// System.out.println(m);
m = clazz.getDeclaredMethod("sayGoodBye", String.class,int.class);
System.out.println(m);
//带Declared的无法获取父类中的方法
// m = clazz.getDeclaredMethod("t1", null);//Exception in thread "main" java.lang.NoSuchMethodException:com.reflex.People.t1()
// System.out.println(m);
}
}

2、调用方法
使用反射调用方法步骤:
①找到被调用方法所在的字节码
②获取到被调用的方法对象
③调用该方法

如何使用反射调用一个方法:
在Method类中有方法:

public Object invoke(Object obj,Object... args):表示调用当前Method所表示的方法

  参数:
obj: 表示被调用方法底层所属对象
Method m = clz.getMethod("sayHi",String.class);
args:表示调用方法是传递的实际参数
返回:
底层方法的返回结果

obj: 表示被调用方法底层所属对象举例说明如下:

class Test {

public String sayHi(String name) {
System.out.println("sayHi()......." + name);
return "XXX";
}
}
sayHi的底层所属对象就是Test的对象:以前调用方法:
Test e = new Test();
String ret = e.sayHi("huangweiyong");

调用私有方法(切记):
在调用私有方法之前:应该设置该方法为可访问的
又因为MethodAccessibleObject子类,所以Method中具有该方法.
sayGoodByeMethod.setAccessible(true);

3、调用静态方法和可变参数方法
使用反射调用静态方法:
public Object invoke(Object obj,Object... args);
如果底层方法是静态的,那么可以忽略指定的 obj参数。将obj参数设置为null即可。

使用反射调用可变参数的方法:
对于数组类型的引用类型的参数,底层会自动解包,为了解决该问题,我们使用Object的一维数组把实际参数包装起来.

(牢记)以后使用反射调用invoke方法,在传递实际参数的时候,无论是基本数据类型还是引用数据类型,也无论是可变参数类型,反正就是一切实际参数都包装在newObject[]{}中,就没问题。


m.invoke(方法底层所属对象,newObject[]{实际参数});通用


下面写个例子加强理解:

public class VarArgsMethodDemo {

public static void main(String[] args) throws Exception {

    Class clazz = Class.forName("com.reflex.VarArgsMethodDemo");
Method m = clazz.getMethod("sum", int[].class);
// m.invoke(null, 1,2,3,4);//error
m.invoke(null, new int[]{1,2,3});//yes
m.invoke(null, new Object[]{new int[]{1,3,4}});//yes
System.out.println("---------------------------"); m = clazz.getMethod("toStr", String[].class);
// m.invoke(null, "A","q","cc");//error
// m.invoke(null, new String[]{"A","q","cc"});//error 引用类型和基本数据类型的区别,基本数据类型可以直接使用,这里会自动解包,我们需要手动包装一层
// 对于数组类型的引用类型的参数,底层会自动解包,为了解决该问题,我们使用Object的一维数组把实际参数包装起来.
//new Object[]{new String[]{"huang ","weiyong"," 18"}} 解包成new String[]{"huang ","weiyong"," 18"}
m.invoke(null, new Object[]{new String[]{"huang ","weiyong"," 18"}});
}
//可变参数底层就是数组
//基本数据类型
public static int sum(int ...args) {
int sum = 0;
for (int i : args) {
sum+=i;
} System.out.println(sum);
return sum;
} //引用数据类型
public static void toStr(String ...args) {
System.out.println(Arrays.toString(args));
}
}

最新文章

  1. Oracle第三方ado.net数据提供程序
  2. SQLServer2008部署镜像
  3. POJ3783Balls[DP 最坏情况最优解]
  4. Web服务精讲–搭个 Web 服务器(二)
  5. ajax与HTML5 history pushState/replaceState实例
  6. 关于SQL Server 中连接查询Join的几种常见用法
  7. spring参数类型异常输出(二), SpringMvc参数类型转换错误输出(二)
  8. [Linux&amp;Vim]基础01
  9. AssetBundle的使用
  10. tensorflow ckpt文件转caffemodel时遇到的坑
  11. tensorflow-变量
  12. python算法练习
  13. MyEclipse中的Tomcat跑大项目时内存溢出:permgen space
  14. 比对软件之STAR的使用方法
  15. apache 服务器概述--安装(一)
  16. BZOJ3534:[SDOI2014]重建(矩阵树定理)
  17. Eclipse下内存溢出错误(OutOfMemoryError)
  18. How to Grid Search Hyperparameters for Deep Learning Models in Python With Keras
  19. ExtJS4.2:自定义主题 入门
  20. 一招搞定多Offer选择

热门文章

  1. nginx中级应用
  2. 在Centos 7 上面 安装MySQL 5.7 简录
  3. Java Integer为代表的包装类
  4. AI_图像识别
  5. HTTP杂项
  6. BZOJ1901 Dynamic Rankings|带修主席树
  7. css3动画(animation)效果3-正方体合成
  8. [Flex] 组件Tree系列 —— 支持CheckBox组件
  9. virsh 连接虚拟机 (vnc 或 控制台)
  10. Kettle 值映射