Java 反射練習

已同步更新至我的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
相關文章
相關標籤/搜索