JAVA反射機制教程

感謝作者無私奉獻,本文屬於轉載,非博客主寫作,包括以下聲明。
特此聲明這些資料的原始內容來自www.java.sun.com,本人只是對其內容在個人的理解的基礎上,進行翻譯和整理。一.概述
Reflection API可以使JAVA代碼動態的查詢和操作正在運行的JAVA類或者接口。Reflection 包含許多的類,例如Method類,該類可以在java.lang.reflect包中找到。
使用Reflection 中的類需要三個步驟:
1.獲取一個要操作的類的對象,該對象屬於java.lang.object包,該對象代表一個正在運行的一個類或接口。下面的三個方法是常用的獲取類對象的方法:
(1) Class c=Class.forname(“java.lang.String”);
使用.forname方法加載一個類,這裏是字符串類,從而獲得一個與該類對應的類對象。
(2) Class c=int.class;
(3) Class c=Integer.TYPE;
2.獲取要操縱的類對象的已經聲明的方法
獲取類對象的方法的最簡單和常用的方法是getDeclareMethods()方法。該方法返回類對象中聲明過的所有方法的一個方法數組(Method[])。還有其他的方法,在後面會有所介紹。
3.利用Reflection API操作類。
二.Java.lang.reflect包介紹
java.lang.reflect包中包含有兩個接口,八個類。
InvocationHandler接口:
Member接口:該接口可以獲取有關類成員(域或者方法)後者構造函數的信息。
AccessibleObject類:該類是域(field)對象、方法(method)對象、構造函數(constructor)對象的基礎類。
Array類:該類提供動態地生成和訪問JAVA數組的方法。
Constructor類:提供一個類的構造函數的信息以及訪問類的構造函數的接口。
Field類:提供一個類的域的信息以及訪問類的域的接口。
Method類:提供一個類的方法的信息以及訪問類的方法的接口。
Modifier類:
Proxy類:提供動態地生成代理類和類實例的靜態方法。
ReflectionPermission類:
三.示例與說明
3.1 查找類中聲明過的所有方法
import java.lang.reflect.*;
   public class method1 {
      private int f1(
       Object p, int x) throws NullPointerException
      {
         if (p == null)
            throw new NullPointerException();
         return x;
      }
       
      public static void main(String args[])
      {
         try {
           Class cls = Class.forName("method1");
       
            Method methlist[]
              = cls.getDeclaredMethods();
            for (int i = 0; i < methlist.length;
               i++) {
               Method m = methlist[i];
               System.out.println("name
                 = " + m.getName());
               System.out.println("decl class = " +
                              m.getDeclaringClass());
               Class pvec[] = m.getParameterTypes();
               for (int j = 0; j < pvec.length; j++)
                  System.out.println("
                   param #" + j + " " + pvec[j]);
               Class evec[] = m.getExceptionTypes();
               for (int j = 0; j < evec.length; j++)
                  System.out.println("exc #" + j
                    + " " + evec[j]);
               System.out.println("return type = " +
                                  m.getReturnType());
               System.out.println("-----");
            }
         }
         catch (Throwable e) {
            System.err.println(e);
         }
      }
   }
代碼說明:
Class cls = Class.forName("method1");獲取一個method1類的類對象cls。
Method methlist[] = cls.getDeclaredMethods();返回一個類聲明的所有方法的方法數組。
m.getDeclaringClass();返回聲明該方法的類的實例。返回值爲一個class。
m.getName():返回該方法的名字,返回值爲字符串類型。
Class pvec[] = m.getParameterTypes():返回該方法的參數的類型的一個數組。注意參數的返回順序是與方法聲明時的順序是相同的。
Class evec[] = m.getExceptionTypes():獲取該方法拋出的例外的一個類型數組。
m.getReturnType():返回該方法的返回值的類型。返回值是一個class。
       除了上述的Method類的方法外,還有別的方法。其中比較重要的有:
Object invoke(Object obj,Object[] args)方法:對該方法進行實際的調用並執行。其中的兩個參數的含義分別是調用該方法的一個類實例對象,和調用該方法的參數對象數組。具體如何應用請參看3.4節。
3.2 獲取構造函數信息
import java.lang.reflect.*;
       
   public class constructor1 {
      public constructor1()
      {
      }
       
      protected constructor1(int i, double d)
      {
      }
       
      public static void main(String args[])
      {
         try {
           Class cls = Class.forName("constructor1");
       
           Constructor ctorlist[]
               = cls.getDeclaredConstructors();
         for (int i = 0; i < ctorlist.length; i++) {
               Constructor ct = ctorlist[i];
               System.out.println("name
                 = " + ct.getName());
               System.out.println("decl class = " +
                            ct.getDeclaringClass());
               Class pvec[] = ct.getParameterTypes();
               for (int j = 0; j < pvec.length; j++)
                  System.out.println("param #"
                     + j + " " + pvec[j]);
               Class evec[] = ct.getExceptionTypes();
               for (int j = 0; j < evec.length; j++)
                  System.out.println(
                    "exc #" + j + " " + evec[j]);
               System.out.println("-----");
            }
          }
          catch (Throwable e) {
             System.err.println(e);
          }
      }
   }
Constructor ctorlist[] = cls.getDeclaredConstructors():獲取該實例對象聲明的所有的構造函數數組。
ct.getName():獲取該構造函數的名稱,返回值是一個字符串類型的變量。
ct.getDeclaringClass():返回聲明該構造函數的類。返回值是一個class。
Class pvec[] = ct.getParameterTypes():返回該構造函數的參數的一個類型數組。返回的是一個class類型的數組。
Class evec[] = ct.getExceptionTypes():返回一個該構造函數的拋出的例外的一個類型數組。
除了上述的方法外,對於Constructor類還有一個很重要的方法:
Object newInstance(Object iniargs[]):實際調用該構造函數並且生成一個實例對象。具體的應用參看3.5節。
3.3 獲取類中域的信息
import java.lang.reflect.*;
       
   public class field1 {
      private double d;
      public static final int i = 37;
      String s = "testing";
       
      public static void main(String args[])
      {
         try {
            Class cls = Class.forName("field1");
       
            Field fieldlist[]
              = cls.getDeclaredFields();
            for (int i
              = 0; i < fieldlist.length; i++) {
               Field fld = fieldlist[i];
               System.out.println("name
                  = " + fld.getName());
               System.out.println("decl class = " +
                           fld.getDeclaringClass());
               System.out.println("type
                  = " + fld.getType());
               int mod = fld.getModifiers();
               System.out.println("modifiers = " +
                          Modifier.toString(mod));
               System.out.println("-----");
            }
          }
          catch (Throwable e) {
             System.err.println(e);
          }
       }
   }
3.4 通過方法名調用方法
import java.lang.reflect.*;
       
   public class method2 {
      public int add(int a, int b)
      {
         return a + b;
      }
       
      public static void main(String args[])
      {
         try {
           Class cls = Class.forName("method2");
           Class partypes[] = new Class[2];
            partypes[0] = Integer.TYPE;
            partypes[1] = Integer.TYPE;
            Method meth = cls.getMethod(
              "add", partypes);
            method2 methobj = new method2();
            Object arglist[] = new Object[2];
            arglist[0] = new Integer(37);
            arglist[1] = new Integer(47);
            Object retobj
              = meth.invoke(methobj, arglist);
            Integer retval = (Integer)retobj;
            System.out.println(retval.intValue());
         }
         catch (Throwable e) {
            System.err.println(e);
         }
      }
   }
       我們會仔細地介紹方法調用的實現。
首先,聲明瞭一個類method2,該類有一個方法public int add(int a, int b)。請注意該方法的方法名’add’、兩個形式參數的數據類型int以及返回值類型int。因爲,這些信息對動態地調用一個類的方法是非常重要的。
       接下來在主調函數中實現的功能如下:
1.Class cls = Class.forName("method2"):獲取類實例對象cls。
2.Class partypes[] = new Class[2];
   partypes[0] = Integer.TYPE;
   partypes[1] = Integer.TYPE;
聲明一個類數組,用來保存兩個參數的數據類型。
3.Method meth = cls.getMethod("add", partypes);注意getMethod方法,該方法將返回一個匹配的方法。匹配的條件,有兩部分來限定。一個是方法名,一個是方法的參數類型數組。(因爲JAVA中允許方法的重載,所以必須說明參數的數據類型)參數類型數組中的各個參數類型的順序必須與方法聲明時的順序相同。
4.method2 methobj = new method2():聲明一個類method2的實例變量。
5.Object arglist[] = new Object[2];
   arglist[0] = new Integer(37);
   arglist[1] = new Integer(47);
聲明一個對象數組,來存儲兩個參數實例。
6.Object retobj = meth.invoke(methobj, arglist):實際調用add函數。注意方法invoke()的兩個參數,methobj是調用方法(或者是聲明方法)的類的一個實例,arglist確實被調用方法(這裏是add方法)的,參數實例數組。返回值仍然是一個對象的實例retobj。
7.Integer retval = (Integer)retobj;
   System.out.println(retval.intValue());將返回的對象實例,進行類型轉換,並輸出。
3.5 生成一個新的實例
import java.lang.reflect.*;
       
   public class constructor2 {
      public constructor2()
      {
      }
       
      public constructor2(int a, int b)
      {
         System.out.println(
           "a = " + a + " b = " + b);
      }
       
      public static void main(String args[])
      {
         try {
           Class cls = Class.forName("constructor2");
           Class partypes[] = new Class[2];
            partypes[0] = Integer.TYPE;
            partypes[1] = Integer.TYPE;
            Constructor ct
              = cls.getConstructor(partypes);
            Object arglist[] = new Object[2];
            arglist[0] = new Integer(37);
            arglist[1] = new Integer(47);
            Object retobj = ct.newInstance(arglist);
         }
         catch (Throwable e) {
            System.err.println(e);
         }
      }
   }
這個例子說明了Constructor類的newInstancce()方法的使用。其具體的過程與3.4節中使用invoke()方法類似,不再多說了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章