通过反射获取及调用方法(Method)

本篇文章包含3个方面分别是:
1、获取方法
使用反射获取某一个类中的方法,步骤:
①找到获取方法所在类的字节码对象
②找到需要被获取的方法

Class类中常用方法:<pre><code>
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

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

测试代码如下:
<pre><code>
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);

}

}
</pre></code>

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

如何使用反射调用一个方法:
在Method类中有方法:
<pre><code>public Object invoke(Object obj,Object... args):表示调用当前Method所表示的方法

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

</pre></code>
obj: 表示被调用方法底层所属对象举例说明如下:
<pre><code>
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");

</pre></code>

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

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

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

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


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


下面写个例子加强理解:
<pre><code>
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));
}

}
</pre></code>

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,332评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,508评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,812评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,607评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,728评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,919评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,071评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,802评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,256评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,576评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,712评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,389评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,032评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,798评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,026评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,473评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,606评论 2 350

推荐阅读更多精彩内容