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();
        }
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章