zoukankan      html  css  js  c++  java
  • 通过反射获取及调用方法(Method)

    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));
    }
    }
  • 相关阅读:
    一款标注颜色,距离的小软件 markman
    EF5+MVC4系列(7) 后台SelectListItem传值给前台显示Select下拉框;后台Action接收浏览器传值的4种方式; 后台Action向前台View视图传递数据的四种方式(ViewDate,TempDate,ViewBag,Model (实际是ViewDate.Model传值))
    ISAPI和CGI限制中没有ASP.NET v4.0 ; vS2013检测到在集成的托管管道模式下不适用的 ASP.NET 设置。
    EF5+MVC4系列(6) 简单三层的搭配(泛型) 实现 增删改查
    MVC4小细节
    目标和制定周期问题
    转 : 设计实例对比:MySQL vs MongoDB
    转:C#通过WebClient/HttpWebRequest实现http的post/get方法
    如何使用 OpenFileDialog 组件 (选择文件组件)
    resharper安装后,F12不能转到定义,也不是反编译,而是转到对象浏览器(object browser)
  • 原文地址:https://www.cnblogs.com/qiumingcheng/p/6785563.html
Copyright © 2011-2022 走看看