已同步更新至我的blog:http://dxjia.cn/2015/08/java-reflect/ html
引用baidubaike上對JAVA反射的說明,以下:JAVA反射機制是在運行狀態中,對於任意一個類,都可以知道這個類的全部屬性和方法(成員變量和函數);對於任意一個對象,都可以調用它的任意一個方法和屬性;這種動態獲取的信息以及動態調用對象的方法的功能稱爲java語言的反射機制。java
而可以使JAVA有這樣的能力,歸根結底是因爲JVM,而小一點說,是由於有Class對象的存在,我在上一篇文章中有講解JAVA的Class對象,它是在類加載完後,每一個類都會產生的一個實例,而其內部詳細描述了這個類的狀況,因此咱們能夠經過這個Class對象來獲得任何有關這個類的細節,不只僅能瞭解這個類,java還提供了方法來動態執行這個類裏的方法或修改爲員變量的值。安全
反射機制的優勢與缺點:(參考:【Java反射機制】)函數
爲何要用反射機制?直接建立對象不就能夠了嗎,這就涉及到了動態與靜態的概念,
靜態編譯:在編譯時肯定類型,綁定對象,即經過。
動態編譯:運行時肯定類型,綁定對象。動態編譯最大限度發揮了java的靈活性,體現了多態的應用,有以下降類之間的藕合性。
一句話,反射機制的優勢就是能夠實現動態建立對象和編譯,體現出很大的靈活性,特別是在J2EE的開發中它的靈活性就表現的十分明顯。好比,一個大型的軟件,不可能一次就把把它設計的很完美,當這個程序編
譯後,發佈了,當發現須要更新某些功能時,咱們不可能要用戶把之前的卸載,再從新安裝新的版本,假如這樣的話,這個軟件確定是沒有多少人用的。採用靜態的話,須要把整個程序從新編譯一次才能夠實現功能
的更新,而採用反射機制的話,它就能夠不用卸載,只須要在運行時才動態的建立和編譯,就能夠實現該功 能。
它的缺點是對性能有影響。使用反射基本上是一種解釋操做,咱們能夠告訴JVM,咱們但願作什麼而且它知足咱們的要求。這類操做老是慢於只直接執行相同的操做。 性能
下面是個人練習程序:測試
在目錄下新建com\dxjia\sample路徑,而後在sample下新建一個UserBean.java的文件,這將是咱們用來進行反射的類。代碼以下:spa
1 package com.dxjia.sample; 2 3 public class UserBean { 4 private String mName; 5 private int mAge; 6 private String mVersion = "1.0"; 7 8 public UserBean() { 9 System.out.println(" UserBean Constructor1 called!"); 10 } 11 12 public UserBean(String name, int age) { 13 System.out.println(" UserBean Constructor2 called!"); 14 init(name, age); 15 } 16 17 public void setName(String name) { 18 mName = name; 19 System.out.println(" UserBean setName() done"); 20 } 21 22 public String getName() { 23 return mName; 24 } 25 26 public void setAge(int age) { 27 mAge = age; 28 System.out.println(" UserBean setAge() done"); 29 } 30 31 public int getAge() { 32 return mAge; 33 } 34 35 private void init(String name, int age) { 36 mName = name; 37 mAge = age; 38 } 39 40 public void printVersion() { 41 System.out.println(" UserBean VERSION: " + mVersion); 42 } 43 44 public void printName() { 45 System.out.println(" UserBean mName [" + mName + "]"); 46 } 47 48 public void printAge() { 49 System.out.println(" UserBean mAge [" + mAge + "]"); 50 } 51 52 private void printUserInfo() { 53 System.out.println(" UserBean mName [" + mName + "] " + "mAge [" + mAge + "]"); 54 } 55 }
而後在根目錄下新建Test.java文件,這裏實現咱們的測試程序,代碼以下【注意註釋】:設計
1 import java.lang.*; 2 import java.lang.reflect.*; 3 4 public class Test { 5 6 public static void main(String[] args) { 7 8 try { 9 Class c = Class.forName("com.dxjia.sample.UserBean"); 10 if (null == c) { 11 System.out.println("can`t load class!"); 12 return; 13 } 14 15 System.out.println("\n--------------獲取類的全部信息----------------------\n"); 16 17 // 獲取類的修飾符,public private... 18 int mod = c.getModifiers(); 19 String modifier = Modifier.toString(mod); 20 System.out.println("modifier : " + modifier); 21 22 // 獲取父類 23 Class superClass = c.getSuperclass(); 24 String superClassName = superClass.getName(); 25 System.out.println("superClassName : " + superClassName); 26 27 // 獲取implements的接口 28 Class[] interfaces = c.getInterfaces(); 29 if (interfaces.length != 0) { 30 for (Class cl : interfaces) { 31 System.out.println("interfacesName : " + cl.getName()); 32 } 33 } else { 34 System.out.println("interfacesName : "); 35 } 36 37 // 獲取全部的成員變量 38 Field[] fields = c.getDeclaredFields(); 39 if (fields.length != 0) { 40 System.out.println("fields : "); 41 for (Field field : fields) { 42 modifier = Modifier.toString(field.getModifiers()); 43 Class type = field.getType(); 44 String name = field.getName(); 45 if (type.isArray()) { 46 String arrType = type.getComponentType().getName() + "[]"; 47 System.out.println(" " + modifier + " " + arrType + " " + name + ";"); 48 } else { 49 System.out.println(" " + modifier + " " + type + " " + name + ";"); 50 } 51 } 52 } else { 53 System.out.println("fields : "); 54 } 55 56 // 獲取全部的構造函數 57 Constructor[] constructors = c.getDeclaredConstructors(); 58 if(constructors.length != 0) { 59 System.out.println("constructors : "); 60 for (Constructor constructor : constructors) { 61 // 構造方法名 62 String name = constructor.getName(); 63 // 獲取訪問修飾符,public private protected 64 modifier = Modifier.toString(constructor.getModifiers()); 65 System.out.print(" " + modifier +" " + name + "("); 66 // 獲取構造方法中的全部參數, paramTypes.length爲0,說明是無參構造函數 67 Class[] paramTypes = constructor.getParameterTypes(); 68 for (int i = 0; i < paramTypes.length; i++) { 69 if (i > 0) { 70 System.out.print(", "); 71 } 72 if (paramTypes[i].isArray()) { 73 System.out.print(paramTypes[i].getComponentType().getName()+"[]"); 74 } else { 75 System.out.print(paramTypes[i].getName()); 76 } 77 } 78 System.out.print(")\n"); 79 } 80 } else { 81 System.out.println("constructors : "); 82 } 83 84 // 獲取全部的成員函數 85 Method[] methods = c.getDeclaredMethods(); 86 if(methods.length != 0) { 87 System.out.println("methods : "); 88 for (Method method: methods) { 89 // 獲取方法的描述符,private public protected... 90 modifier = Modifier.toString(method.getModifiers()); 91 // 獲取方法的返回類型 92 Class returnType = method.getReturnType(); 93 if (returnType.isArray()) { 94 String arrType = returnType.getComponentType().getName()+"[]"; 95 System.out.print(" " + modifier + " " + arrType + " " + method.getName() + "("); 96 } else { 97 System.out.print(" " + modifier + " " + returnType.getName() + " " + method.getName() + "("); 98 } 99 // 獲取全部的參數信息 100 Class[] paramTypes = method.getParameterTypes(); 101 for (int i = 0; i < paramTypes.length; i++) { 102 if (i > 0) { 103 System.out.print(","); 104 } 105 if (paramTypes[i].isArray()) { 106 System.out.println(paramTypes[i].getComponentType().getName()+"[]"); 107 } else { 108 System.out.print(paramTypes[i].getName()); 109 } 110 } 111 System.out.println(");"); 112 } 113 } else { 114 System.out.println("methods : "); 115 } 116 117 System.out.println("\n----------------測試使用----------------------\n"); 118 119 /** 120 * 測試反射,調用函數,變量賦值等 121 * 反射的使用通常都會先像上面這樣打印出來,進行一個分析以後, 122 * 再編寫相似下面的代碼來反射調用類的函數,也就是本身先經過上面的方式來了解這個類, 123 * 而後再hard code反射使用這個類中對本身有用的函數來達到目的。固然,咱們比較瞭解那個類了,只是環境中沒有公開,因此咱們須要反射 124 */ 125 // 首先能夠實例化對象,由於萬物都繼承自Object 126 // 因此這裏用Object來聲明定義對象,不影響使用 127 // 直接使用Class.newInstance()函數,是調用的類的無參構造函數 128 System.out.println("調用無參構造函數"); 129 Object bean1 = c.newInstance(); 130 131 // 若是要調用有參構造函數,那就要使用下面的方式 132 Class[] paramTypes = {String.class, int.class}; 133 Constructor con = c.getConstructor(String.class, int.class); 134 // 使用 135 System.out.println("調用有參構造函數"); 136 Object bean2 = con.newInstance("小明", 16); 137 138 // 調用bean2 public 函數 printVersion() 139 System.out.println("執行public printVersion()"); 140 Method method1 = c.getDeclaredMethod("printVersion"); 141 method1.invoke(bean2); 142 143 // 調用bean2 private函數 printUserInfo() 144 System.out.println("執行public printUserInfo()"); 145 Method method2 = c.getDeclaredMethod("printUserInfo"); 146 // 由於printUserInfo是private方法,因此須要加上這句來避免安全檢查,這樣才能夠調用私有方法 147 method2.setAccessible(true); 148 // 執行 149 method2.invoke(bean2); 150 151 // 調用有參數的函數 setName() setAge() 152 System.out.println("調用有參數函數設置新name和age"); 153 Method method3 = c.getDeclaredMethod("setName", String.class); 154 method3.invoke(bean2, "張三"); 155 Method method4 = c.getDeclaredMethod("setAge", int.class); 156 method4.invoke(bean2, 25); 157 158 // 調用 printUserInfo 將新值打印出來 159 System.out.println("打印新值"); 160 method2.invoke(bean2); 161 162 // 直接操做成員變量,給私有成員變量賦值,記得加setAccessible(true); 163 Field field = c.getDeclaredField("mVersion"); 164 field.setAccessible(true); 165 String oldVersion = (String) field.get(bean2); 166 System.out.println("直接獲取私有變量mVersion的值,並打印:" + oldVersion); 167 System.out.println("直接將私有成員變量mVersion賦值2.0"); 168 field.set(bean2, "2.0"); 169 // 調用printVersion()打印新值 170 System.out.println("打印新值"); 171 method1.invoke(bean2); 172 } catch (ClassNotFoundException e) { 173 System.out.println("exception: " + e.toString()); 174 } catch (InstantiationException e) { 175 System.out.println("exception: " + e.toString()); 176 } catch (IllegalAccessException e) { 177 System.out.println("exception: " + e.toString()); 178 } catch (NoSuchMethodException e) { 179 System.out.println("exception: " + e.toString()); 180 } catch (InvocationTargetException e) { 181 System.out.println("exception: " + e.toString()); 182 } catch (NoSuchFieldException e) { 183 System.out.println("exception: " + e.toString()); 184 } 185 } 186 187 }
打開cmd,切換到該目錄下,執行code
1 javac com\dxjia\sample\UserBean.java 2 javac -encoding UTF-8 -Xlint:unchecked Test.java
編譯經過後,執行:htm
1 java Test
打印以下:
--------------獲取類的全部信息---------------------- modifier : public superClassName : java.lang.Object interfacesName : fields : private class java.lang.String mName; private int mAge; private class java.lang.String mVersion; constructors : public com.dxjia.sample.UserBean() public com.dxjia.sample.UserBean(java.lang.String, int) methods : public int getAge(); public void printName(); public void printAge(); public java.lang.String getName(); private void init(java.lang.String,int); public void setName(java.lang.String); public void setAge(int); public void printVersion(); private void printUserInfo(); ----------------測試使用---------------------- 調用無參構造函數 UserBean Constructor1 called! 調用有參構造函數 UserBean Constructor2 called! 執行public printVersion() UserBean VERSION: 1.0 執行public printUserInfo() UserBean mName [小明] mAge [16] 調用有參數函數設置新name和age UserBean setName() done UserBean setAge() done 打印新值 UserBean mName [張三] mAge [25] 直接獲取私有變量mVersion的值,並打印:1.0 直接將私有成員變量mVersion賦值2.0 打印新值 UserBean VERSION: 2.0