反射機制作用
- 在執行時分析類的能力
- 在執行時檢視物件
- 實現通用的陣列操作程式碼
反射機制的實現
採用Class類和java.lang.reflect 類庫一起實現 <反射>機制
- Class 類: 代表一個目標類。
- Field 類: 代表目標類的成員變數。
- Method 類: 代表目標類的方法。
- Constructor 類: 代表目標類的構造方法。
- Array 類: 提供了動態建立陣列,以及訪問陣列的元素的靜態方法。
Class 類
在程式執行期間,Java執行時系統始終為所有的物件維護一個被稱為執行時的型別表示。這個資訊跟蹤著每個物件所屬的類。虛擬機器利用執行時型別資訊選擇相應的方法執行。
然而,可以通過專門的Java類訪問這些資訊。儲存這些資訊的類被成為Class,這個名字很容易讓人混淆。Object 類中的getClass() 方法將返回一個Class型別的例項。
獲取Class物件的三種方法
- 如果類在一個包裡,包的名字也作為做類名的一部分。
Random generator = new Random();
Class cl = generator.getClass();
System.out.println(cl.getName());//java.util.Random
複製程式碼
-
如果類名儲存字串中,並可在執行時該變,即可使用這種方法。forName() 方法會爆ClassNotFoundException 異常,所以需要進行異常處理。
Class.forName() 內部通過反射API根據目標類名將類手動載入到記憶體中,稱為類載入器載入方法。載入過程中會把目標類的static方法,變數,程式碼塊載入到JVM,注意此時尚未建立物件例項
String className = "java.util.Random";
Class cl = class.forName(className);
複製程式碼
- 如果T是任意的Java型別(或void 關鍵字),T.class 將代表匹配的類物件
Class cl = Random.class;
複製程式碼
獲取構造器–Constructor 類
Constructor[] getConstructors()
:獲得所有public構造器;Constructor[] getDeclaredConstructors()
:獲得所有訪問許可權的構造器Constructor getConstructor(Class[] params)
:根據指定引數獲得對應構造器;Constructor getDeclaredConstructor(Class[] params)
:根據指定引數獲得對應構造器;
獲得方法–Method 類
Method[] getMethods()
:獲得所有public方法;Method[] getDeclaredMethods()
:獲得所有訪問許可權的方法;Method getMethod(String name, Class[] params)
:根據方法簽名獲取類自身對應public方法,或者從基類繼承和介面實現的對應public方法;Method getDeclaredMethod(String name, Class[] params)
:根據方法簽名獲得對應的類自身宣告方法,訪問許可權不限;
獲得變數–Field 類
Field[] getFields()
:獲得類中所有public變數Field[] getDeclaredFields()
:獲得類中所有訪問許可權變數Field getField(String name)
:根據變數名得到對應的public變數Field getDeclaredField(String name)
:根據變數名獲得對應的變數,訪問許可權不限;
實戰
我們來個例子加深一下印象。
列印一個類的所有建構函式
public static void printConstructors(Class cl)
{
//返回包含Constructor 物件的陣列,其中包含了Class物件的所有構造器
Constructor[] constructors = cl.getDeclaredConstructors();
for (Constructor c: constructors) {
//String getName()
//返回一個用於描述構造器、方法或域名的字串
String name = c.getName();
System.out.print(" ");
String modifiers = Modifier.toString(c.getModifiers());
if (modifiers.length()>0)
System.out.print(modifiers+ " ");
System.out.print(name+"(");
//Class[] getParameterTypes() (在Constructor 和 Method 類中)
//返回一個用於描述引數型別的Class物件陣列
printParameterType(c.getParameterTypes());
System.out.println(");");
}
}
複製程式碼
列印一個類的所有方法
public static void printMethods(Class cl)
{
//返回包含Method 物件的陣列,返回這個類或介面的全部方法,但不包括由超類繼承了的方法
Method[] methods = cl.getDeclaredMethods();
for (Method m:methods) {
//Class getReturnType() (在 Method 類中)
//返回一個用於描述返回型別的Class物件
Class retType = m.getReturnType();
String name = m.getName();
System.out.print(" ");
//列印修飾符、返回型別和方法名稱
String modifiers =Modifier.toString(m.getModifiers());
if (modifiers.length()>0)
System.out.print(modifiers+" ");
System.out.print(retType.getName()+" "+ name + "(");
printParameterType(m.getParameterTypes());
System.out.println(");");
}
}
複製程式碼
列印一個類的所有欄位
public static void printFields(Class cl)
{
//Field[] getDeclaredFields()
//返回包含Field 物件的陣列,這些物件記錄了這個類的全部域
Field[] fields = cl.getDeclaredFields();
for (Field f : fields){
Class type = f.getType();
String name = f.getName();
System.out.print(" ");
String modifiers = Modifier.toString(f.getModifiers());
if (modifiers.length()>0)
System.out.print(modifiers+" ");
System.out.println(type.getName()+" "+ name+ ";");
}
}
複製程式碼
列印方法的引數型別
public static void printParameterType(Class[] paramTypes)
{
for (int j = 0;j<paramTypes.length;j++) {
if (j>0)
System.out.print(", ");
System.out.print(paramTypes[j].getName());
}
}
複製程式碼
測試
public static void main(String[] args)
{
String name;
if (args.length>0)
name = args[0];
else {
Scanner in = new Scanner(System.in);
System.out.println("Enter class name(e.g java.util.Date): ");
name = in.next();
}
try {
//print class name and superclass name (if != object)
//呼叫Class 的靜態方法 forName 獲得類名對應的Class 物件
Class cl = Class.forName(name);
//獲取父類所對應的Class 物件
Class supercl = cl.getSuperclass();
//返回對應modifiers 中位設定的修飾符的字串表示
String modifiers = Modifier.toString(cl.getModifiers());
if (modifiers.length()>0)
System.out.print(modifiers+" ");
System.out.print("class "+ name);
//判斷是否有繼承父類
if (supercl != null && supercl != Object.class)
System.out.print(" extends "+ supercl.getName());
System.out.print("
{
");
printConstructors(cl);
System.out.println();
printMethods(cl);
System.out.println();
printFields(cl);
System.out.println("}");
}catch (ClassNotFoundException ex) {
ex.printStackTrace();
}
System.exit(0);
}
複製程式碼