Java 反射练习
已同步更新至個人blog:http://dxjia.cn/2015/08/java-reflect/ ? ?
引用baidubaike上對JAVA反射的說明,如下:JAVA反射機制是在運行狀態中,對于任意一個類,都能夠知道這個類的所有屬性和方法(成員變量和函數);對于任意一個對象,都能夠調用它的任意一個方法和屬性;這種動態獲取的信息以及動態調用對象的方法的功能稱為java語言的反射機制。
? ? 而能夠使JAVA有這樣的能力,歸根結底是由于JVM,而小一點說,是因為有Class對象的存在,我在上一篇文章中有講解JAVA的Class對象,它是在類加載完后,每個類都會產生的一個實例,而其內部詳細描述了這個類的情況,所以我們可以通過這個Class對象來得到任何有關這個類的細節,不僅僅能了解這個類,java還提供了方法來動態執行這個類里的方法或修改成員變量的值。
反射機制的優點與缺點:(參考:【Java反射機制】)
為什么要用反射機制?直接創建對象不就可以了嗎,這就涉及到了動態與靜態的概念,
靜態編譯:在編譯時確定類型,綁定對象,即通過。
動態編譯:運行時確定類型,綁定對象。動態編譯最大限度發揮了java的靈活性,體現了多態的應用,有以降低類之間的藕合性。
一句話,反射機制的優點就是可以實現動態創建對象和編譯,體現出很大的靈活性,特別是在J2EE的開發中它的靈活性就表現的十分明顯。比如,一個大型的軟件,不可能一次就把把它設計的很完美,當這個程序編
譯后,發布了,當發現需要更新某些功能時,我們不可能要用戶把以前的卸載,再重新安裝新的版本,假如這樣的話,這個軟件肯定是沒有多少人用的。采用靜態的話,需要把整個程序重新編譯一次才可以實現功能
的更新,而采用反射機制的話,它就可以不用卸載,只需要在運行時才動態的創建和編譯,就可以實現該功 能。
它的缺點是對性能有影響。使用反射基本上是一種解釋操作,我們可以告訴JVM,我們希望做什么并且它滿足我們的要求。這類操作總是慢于只直接執行相同的操作。
?
下面是我的練習程序:
在目錄下新建com\dxjia\sample路徑,然后在sample下新建一個UserBean.java的文件,這將是我們用來進行反射的類。代碼如下:
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,切換到該目錄下,執行
1 javac com\dxjia\sample\UserBean.java 2 javac -encoding UTF-8 -Xlint:unchecked Test.java編譯通過后,執行:
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和ageUserBean setName() doneUserBean setAge() done 打印新值UserBean mName [張三] mAge [25] 直接獲取私有變量mVersion的值,并打印:1.0 直接將私有成員變量mVersion賦值2.0 打印新值UserBean VERSION: 2.0?
轉載于:https://www.cnblogs.com/flyme/p/4577113.html
總結
- 上一篇: GridControl详解(八)菜单
- 下一篇: 团队博客第五周 运行与总结