通過反射獲取及調用方法(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)); } }


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM