java动态反射调用方法

比如说现在有一个类:

package com.test;

class Function {

    public void print(String s, Integer i) {
        System.out.println("print:String+int:"+s+i);
    }

    public void print(String s1, String s2) {
        System.out.println("print:String+String:"+s1+s2);
    }

    ......
}

现在需要你来封装一个方法,比如说传给你方法名参数列表,然后调用相应的方法,这样只能是通过java的反射机制来实现,相关的方法如下:

(1)已经实例化该类:

   /**
     * 通过实体类与方法名和参数列表来反射调用方法
     * @param obj
     *          已经实例化的类
     * @param methodName
     *          方法名称
     * @param args
     *          参数数组
     */
    public static void methodReflect(Object obj, String methodName, Object[] args) {

        Class[] argsClass = new Class[args.length];

        for(int i=0; i<args.length; i++) {
            argsClass[i] = args[i].getClass(); //获得每一个参数的实际类型
        }

        try {

            Method methodReflect = obj.getClass().getMethod(methodName, argsClass);//反射获得方法
            methodReflect.invoke(obj, args);    //调用此方法
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (SecurityException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }

相关的测试:

 public static void main(String[] args) {
      Function fun = new Function();
      Object[] argsArr = {"hello", 1};
      methodReflect(fun, "print", argsArr);
    }

然后便可打印:

print:String+int:hello1

当然,如果你传入参数数组是两个字符串:

 public static void main(String[] args) {
      Function fun = new Function();
      Object[] argsArr = {"hello", "world"};
      methodReflect(fun, "print", argsArr);
    }

便可打印:

print:String+String:helloworld

(2)只知道类的路径跟名称:

   /**
     * 通过类的名称与方法名和参数列表来反射调用方法
     * @param className
     *              类所在的路径
     * @param methodName
     *              方法的名称
     * @param args
     *          参数的列表
     */
    public static void methodReflect(String className, String methodName, Object[] args) {

        Class[] argsClass = new Class[args.length];

        for(int i=0; i<args.length; i++) {
            argsClass[i] = args[i].getClass();  //获得每一个参数的实际类型
        }

        try {

            Class c = Class.forName(className); //通过类名获得Class
            Object obj = c.newInstance();   //实例化类
            Method methodReflect = obj.getClass().getMethod(methodName, argsClass); //反射获得方法
            methodReflect.invoke(obj, args);    //调用此方法

        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (SecurityException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        }
    }

测试方法如下:

 public static void main(String[] args) {
        Object[] argsArr = {"hello", 1};
        methodReflect("com.test.Function", "print", argsArr);
    }

测试结果会得到与上面相同的效果。

注意:经过测试好像反射并没有自动解箱跟封箱的功能,如果你在Function类里面的print方法改为下面的代码:

    public void print(String s, int i) {
        System.out.println("print:String+int:"+s+i);
    }

这样不管你测试方法里面的参数数组是下面的哪种写法都会报找不到对应方法的异常:

Object[] argsArr = {"hello", 1};

or

Object[] argsArr = {"hello", new Integer(1)};

所以如果要反射调用方法,方法参数不要用基本数据类型,要转换成对应的封装类。

贴上完整的代码:

package com.test;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

class Function {

    public void print(String s, int i) {
        System.out.println("print:String+int:"+s+i);
    }

    public void print(String s1, String s2) {
        System.out.println("print:String+String:"+s1+s2);
    }

}

public class ReflectTest {
    public static void main(String[] args) {
/*        Function fun = new Function();
        Object[] argsArr = {"hello", 1};
        methodReflect(fun, "print", argsArr);*/
        Object[] argsArr = {"hello", 1};
        methodReflect("com.shangpin.model.Function", "print", argsArr);
    }

    /**
     * 通过实体类与方法名和参数列表来反射调用方法
     * @param obj
     *          已经实例化的类
     * @param methodName
     *          方法名称
     * @param args
     *          参数数组
     */
    public static void methodReflect(Object obj, String methodName, Object[] args) {

        Class[] argsClass = new Class[args.length];

        for(int i=0; i<args.length; i++) {
            argsClass[i] = args[i].getClass(); //获得每一个参数的实际类型
        }

        try {

            Method methodReflect = obj.getClass().getMethod(methodName, argsClass);//反射获得方法
            methodReflect.invoke(obj, args);    //调用此方法
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (SecurityException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }

    /**
     * 通过类的名称与方法名和参数列表来反射调用方法
     * @param className
     *              类所在的路径
     * @param methodName
     *              方法的名称
     * @param args
     *          参数的列表
     */
    public static void methodReflect(String className, String methodName, Object[] args) {

        Class[] argsClass = new Class[args.length];

        for(int i=0; i<args.length; i++) {
            argsClass[i] = args[i].getClass();  //获得每一个参数的实际类型
        }

        try {

            Class c = Class.forName(className); //通过类名获得Class
            Object obj = c.newInstance();   //实例化类
            Method methodReflect = obj.getClass().getMethod(methodName, argsClass); //反射获得方法
            methodReflect.invoke(obj, args);    //调用此方法

        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (SecurityException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        }
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章