飛翔的起點

          從這里出發(fā)

          導(dǎo)航

          <2009年1月>
          28293031123
          45678910
          11121314151617
          18192021222324
          25262728293031
          1234567

          統(tǒng)計

          常用鏈接

          留言簿(5)

          隨筆分類

          隨筆檔案

          文章分類

          文章檔案

          搜索

          最新評論

          閱讀排行榜

          評論排行榜

          反射機(jī)制補(bǔ)充

          本篇文章為在工作中使用JAVA反射的經(jīng)驗總結(jié),也可以說是一些小技巧,以后學(xué)會新的小技巧,會不斷更新。

                  在開始之前,我先定義一個測試類Student,代碼如下:

          1. package chb.test.reflect;   
          2.   
          3. public class Student {   
          4.     private int age;   
          5.     private String name;   
          6.     public int getAge() {   
          7.         return age;   
          8.      }   
          9.     public void setAge(int age) {   
          10.         this.age = age;   
          11.      }   
          12.     public String getName() {   
          13.         return name;   
          14.      }   
          15.     public void setName(String name) {   
          16.         this.name = name;   
          17.      }   
          18.        
          19.     public static void hi(int age,String name){   
          20.          System.out.println("大家好,我叫"+name+",今年"+age+"歲");   
          21.      }   
          22. }<PRE></PRE>  

          一、JAVA反射的常規(guī)使用步驟

              反射調(diào)用一般分為3個步驟:

          • 得到要調(diào)用類的class
          • 得到要調(diào)用的類中的方法(Method)
          • 方法調(diào)用(invoke)

               代碼示例:

          1. Class cls = Class.forName("chb.test.reflect.Student");   
          2. Method m = cls.getDeclaredMethod("hi",new Class[]{int.class,String.class});   
          3. m.invoke(cls.newInstance(),20,"chb");<PRE></PRE>  

          二、方法調(diào)用中的參數(shù)類型

                  在方法調(diào)用中,參數(shù)類型必須正確,這里需要注意的是不能使用包裝類替換基本類型,比如不能使用Integer.class代替int.class。

                 如我要調(diào)用Student的setAge方法,下面的調(diào)用是正確的:

          1. Class cls = Class.forName("chb.test.reflect.Student");   
          2. Method setMethod = cls.getDeclaredMethod("setAge",int.class);   
          3. setMethod.invoke(cls.newInstance(), 15);<PRE></PRE>  

           

                 而如果我們用Integer.class替代int.class就會出錯,如:

          1. Class cls = Class.forName("chb.test.reflect.Student");   
          2. Method setMethod = cls.getDeclaredMethod("setAge",Integer.class);   
          3. setMethod.invoke(cls.newInstance(), 15);<PRE></PRE>  

           

                 jvm會報出如下異常:

          1. java.lang.NoSuchMethodException: chb.test.reflect.Student.setAge(java.lang.Integer)   
          2.      at java.lang.Class.getDeclaredMethod(Unknown Source)   
          3.      at chb.test.reflect.TestClass.testReflect(TestClass.java:23)<PRE></PRE>  

           

          三、static方法的反射調(diào)用

           

                 static方法調(diào)用時,不必得到對象示例,如下:

          1. Class cls = Class.forName("chb.test.reflect.Student");   
          2. Method staticMethod = cls.getDeclaredMethod("hi",int.class,String.class);   
          3. staticMethod.invoke(cls,20,"chb");//這里不需要newInstance   
          4. //staticMethod.invoke(cls.newInstance(),20,"chb");<PRE></PRE>  

          四、private的成員變量賦值

              如果直接通過反射給類的private成員變量賦值,是不允許的,這時我們可以通過setAccessible方法解決。代碼示例:

          1. Class cls = Class.forName("chb.test.reflect.Student");   
          2. Object student = cls.newInstance();//得到一個實例   
          3. Field field = cls.getDeclaredField("age");   
          4. field.set(student, 10);   
          5. System.out.println(field.get(student));<PRE></PRE>  

           

               運行如上代碼,系統(tǒng)會報出如下異常:

          1. java.lang.IllegalAccessException: Class chb.test.reflect.TestClass can not access a member of class chb.test.reflect.Student with modifiers "private"   
          2.      at sun.reflect.Reflection.ensureMemberAccess(Unknown Source)   
          3.      at java.lang.reflect.Field.doSecurityCheck(Unknown Source)   
          4.      at java.lang.reflect.Field.getFieldAccessor(Unknown Source)   
          5.      at java.lang.reflect.Field.set(Unknown Source)   
          6.      at chb.test.reflect.TestClass.testReflect(TestClass.java:20)<PRE></PRE>  

              解決方法:

          1. Class cls = Class.forName("chb.test.reflect.Student");   
          2. Object student = cls.newInstance();   
          3. Field field = cls.getDeclaredField("age");   
          4. field.setAccessible(true);//設(shè)置允許訪問   
          5. field.set(student, 10);   
          6. System.out.println(field.get(student));<PRE></PRE>  

              其實,在某些場合下(類中有g(shù)et,set方法),可以先反射調(diào)用set方法,再反射調(diào)用get方法達(dá)到如上效果,代碼示例:

          1. Class cls = Class.forName("chb.test.reflect.Student");   
          2. Object student = cls.newInstance();   
          3.   
          4. Method setMethod = cls.getDeclaredMethod("setAge",Integer.class);   
          5. setMethod.invoke(student, 15);//調(diào)用set方法   
          6.                
          7. Method getMethod = cls.getDeclaredMethod("getAge");   
          8. System.out.println(getMethod.invoke(student));//再調(diào)用get方法<PRE></PRE>

          posted on 2009-01-11 17:28 forgood 閱讀(1207) 評論(1)  編輯  收藏 所屬分類: java

          評論

          # re: 反射機(jī)制補(bǔ)充 2009-01-11 17:52 forgood

          JAVA反射機(jī)制
          JAVA反射機(jī)制是在運行狀態(tài)中,對于任意一個類,都能夠知道這個類的所有屬性和方法;對于任意一個對象,都能夠調(diào)用它的任意一個方法;這種動態(tài)獲取的信息以及動態(tài)調(diào)用對象的方法的功能稱為java語言的反射機(jī)制。
          Java反射機(jī)制主要提供了以下功能: 在運行時判斷任意一個對象所屬的類;在運行時構(gòu)造任意一個類的對象;在運行時判斷任意一個類所具有的成員變量和方法;在運行時調(diào)用任意一個對象的方法;生成動態(tài)代理。
          1. 得到某個對象的屬性

          1 public Object getProperty(Object owner, String fieldName) throws Exception {
          2 Class ownerClass = owner.getClass();
          3
          4 Field field = ownerClass.getField(fieldName);
          5
          6 Object property = field.get(owner);
          7
          8 return property;
          9 }
          Class ownerClass = owner.getClass():得到該對象的Class。

          Field field = ownerClass.getField(fieldName):通過Class得到類聲明的屬性。

          Object property = field.get(owner):通過對象得到該屬性的實例,如果這個屬性是非公有的,這里會報IllegalAccessException。

          2. 得到某個類的靜態(tài)屬性

          1 public Object getStaticProperty(String className, String fieldName)
          2 throws Exception {
          3 Class ownerClass = Class.forName(className);
          4
          5 Field field = ownerClass.getField(fieldName);
          6
          7 Object property = field.get(ownerClass);
          8
          9 return property;
          10 }

          Class ownerClass = Class.forName(className) :首先得到這個類的Class。

          Field field = ownerClass.getField(fieldName):和上面一樣,通過Class得到類聲明的屬性。

          Object property = field.get(ownerClass) :這里和上面有些不同,因為該屬性是靜態(tài)的,所以直接從類的Class里取。

          3. 執(zhí)行某對象的方法

          1 public Object invokeMethod(Object owner, String methodName, Object[] args) throws Exception {
          2
          3 Class ownerClass = owner.getClass();
          4
          5 Class[] argsClass = new Class[args.length];
          6
          7 for (int i = 0, j = args.length; i < j; i++) {
          8 argsClass[i] = args[i].getClass();
          9 }
          10
          11 Method method = ownerClass.getMethod(methodName, argsClass);
          12
          13 return method.invoke(owner, args);
          14 }
          Class owner_class = owner.getClass() :首先還是必須得到這個對象的Class。

          5~9行:配置參數(shù)的Class數(shù)組,作為尋找Method的條件。

          Method method = ownerClass.getMethod(methodName, argsClass):通過Method名和參數(shù)的Class數(shù)組得到要執(zhí)行的Method。

          method.invoke(owner, args):執(zhí)行該Method,invoke方法的參數(shù)是執(zhí)行這個方法的對象,和參數(shù)數(shù)組。返回值是Object,也既是該方法的返回值。

          4. 執(zhí)行某個類的靜態(tài)方法

          1 public Object invokeStaticMethod(String className, String methodName,
          2 Object[] args) throws Exception {
          3 Class ownerClass = Class.forName(className);
          4
          5 Class[] argsClass = new Class[args.length];
          6
          7 for (int i = 0, j = args.length; i < j; i++) {
          8 argsClass[i] = args[i].getClass();
          9 }
          10
          11 Method method = ownerClass.getMethod(methodName, argsClass);
          12
          13 return method.invoke(null, args);
          14 }

          基本的原理和實例3相同,不同點是最后一行,invoke的一個參數(shù)是null,因為這是靜態(tài)方法,不需要借助實例運行。

          5. 新建實例
          1
          2 public Object newInstance(String className, Object[] args) throws Exception {
          3 Class newoneClass = Class.forName(className);
          4
          5 Class[] argsClass = new Class[args.length];
          6
          7 for (int i = 0, j = args.length; i < j; i++) {
          8 argsClass[i] = args[i].getClass();
          9 }
          10
          11 Constructor cons = newoneClass.getConstructor(argsClass);
          12
          13 return cons.newInstance(args);
          14
          15 }

          這里說的方法是執(zhí)行帶參數(shù)的構(gòu)造函數(shù)來新建實例的方法。如果不需要參數(shù),可以直接使用newoneClass.newInstance()來實現(xiàn)。

          Class newoneClass = Class.forName(className):第一步,得到要構(gòu)造的實例的Class。

          第5~第9行:得到參數(shù)的Class數(shù)組。

          Constructor cons = newoneClass.getConstructor(argsClass):得到構(gòu)造子。

          cons.newInstance(args):新建實例。

          6. 判斷是否為某個類的實例

          1 public boolean isInstance(Object obj, Class cls) {
          2 return cls.isInstance(obj);
          3 }

          7. 得到數(shù)組中的某個元素
          1 public Object getByArray(Object array, int index) {
          2 return Array.get(array,index);
          3 }


            回復(fù)  更多評論   

          主站蜘蛛池模板: 靖远县| 镇宁| 双流县| 莲花县| 江孜县| 宁夏| 双牌县| 灵台县| 道孚县| 泗洪县| 大城县| 吉木萨尔县| 阳泉市| 宾阳县| 浦江县| 盐山县| 佛山市| 临西县| 新野县| 沙湾县| 仙桃市| 楚雄市| 西藏| 濉溪县| 眉山市| 呼图壁县| 西乌珠穆沁旗| 曲靖市| 张掖市| 循化| 嘉禾县| 乐昌市| 越西县| 永州市| 大新县| 海盐县| 五常市| 成安县| 电白县| 连江县| 陵川县|