Java反射(Reflection)

來源:互聯網
上載者:User

標籤:

基本概念

  在Java運行時環境中,對於任意一個類,能否知道這個類有哪些屬性和方法?對於任意一個對象,能否調用它的任意一個方法?

  答案是肯定的。

  這種動態擷取類的資訊以及動態調用對象的方法的功能來自於Java語言的反射(Reflection)機制

  

  Java反射機制主要提供了以下功能:

  1.在運行時判斷任意一個對象所屬的類。

  2.在運行時構造任意一個類的對象。

  3.在運行時判斷任意一個類所具有的成員變數和方法。

  4.在運行時調用任意一個對象的方法。

      5.在運行時設定任意一個對象的屬性值。

  Reflection是Java被視為動態(或准動態)語言的一個關鍵性質。

  這個機制允許程式在運行時透過Reflection APIs取得任何一個已知名稱的class的內部資訊。

  包括其modifiers(諸如public、static等)、 superclass(例如Object)、實現了的 interfaces (例如Serializable)、也包括其constuctors,fields和methods的所有資訊,並可於運行時改變fields內容或調用methods。

 

動態語言

  動態語言的定義“程式運行時,允許改變程式結構或者變數類型,這種語言稱為動態語言”。

  從這個觀點看,Perl,Python,Ruby是動態語言,C++,Java,C#不是動態語言。

  儘管在這樣的定義與分類下Java不是動態語言,它卻有著一個非常突出的動態相關機制:Reflection。這個字的意思是:反射、映像、倒影,用在Java身上指的是我們可以於運行時載入、探知、使用編譯期間完全未知的classes。

  換句話說,Java程式可以載入一個運行時才得知名稱的class,獲悉其完整構造(但不包括methods定義),並產生其對象實體、或對其fields設值、或喚起其methods。

  這種“看透”class的能力(the ability of the program to examine itself)被稱為introspection(內省、內觀、反省)。Reflectionintrospection是常被並提的兩個術語。

 

Java Reflection API簡介

  在JDK中,主要由以下類來實現Java反射機制,這些類(除了第一個)都位於java.lang.reflect包中

  Class類:代表一個類,位於java.lang包下。

  Field類:代表類的成員變數(成員變數也稱為類的屬性)。

  Method類:代表類的方法。

  Constructor類:代表類的構造方法。

  Array類:提供了動態建立數組,以及訪問數組的元素的靜態方法。

 

Class對象

  要想使用反射,首先需要獲得待操作的類所對應的Class對象。

  Java中,無論產生某個類的多少個對象,這些對象都會對應於同一個Class對象。

  這個Class對象是由JVM產生的,通過它能夠獲悉整個類的結構。

 

  常用的擷取Class對象的3種方式:

  1.使用Class類的靜態方法。例如:  

Class.forName("java.lang.String");

 

  2.使用類的.class文法。如:

String.class;

 

  3.使用對象的getClass()方法。如:

String str = "aa";Class<?> classType1 = str.getClass();

 

  getClass()方法定義在Object類中,不是靜態方法,需要通過對象來調用,並且它聲明為final,表明不能被子類所覆寫。

  直接print所獲得的Class對象classType會輸出:

    class 完整類名

  如果調用該Class對象的getName()方法,則輸出完整類名,不加class。

 

常式1:擷取方法

  常式DumpMethods類示範了Reflection API的基本作用,它讀取命令列參數指定的類名,然後列印這個類所具有的方法資訊。 

import java.lang.reflect.Method;public class DumpMethods{    public static void main(String[] args) throws Exception //在方法後加上這句,異常就消失了    {        //獲得字串所標識的類的class對象        Class<?> classType = Class.forName("java.lang.String");//在此處傳入字串指定類名,所以參數擷取可以是一個運行期的行為,可以用args[0]                //返回class對象所對應的類或介面中,所聲明的所有方法的數組(包括私人方法)        Method[] methods = classType.getDeclaredMethods();                //遍曆輸出所有方法聲明        for(Method method : methods)        {            System.out.println(method);        }    }}

 

 

常式2:通過反射調用方法

  通過反射調用方法。詳情見代碼及注釋:

 

import java.lang.reflect.Method;public class InvokeTester{    public int add(int param1, int param2)    {        return param1 + param2;    }    public String echo(String message)    {        return "Hello: " + message;    }    public static void main(String[] args) throws Exception    {        // 以前的常規執行手段        InvokeTester tester = new InvokeTester();        System.out.println(tester.add(1, 2));        System.out.println(tester.echo("Tom"));        System.out.println("---------------------------");        // 通過反射的方式        // 第一步,擷取Class對象        // 前面用的方法是:Class.forName()方法擷取        // 這裡用第二種方法,類名.class        Class<?> classType = InvokeTester.class;        // 產生新的對象:用newInstance()方法        Object invokeTester = classType.newInstance();        System.out.println(invokeTester instanceof InvokeTester); // 輸出true        // 通過反射調用方法        // 首先需要獲得與該方法對應的Method對象        Method addMethod = classType.getMethod("add", new Class[] { int.class,                int.class });        // 第一個參數是方法名,第二個參數是這個方法所需要的參數的Class對象的數組        // 調用目標方法        Object result = addMethod.invoke(invokeTester, new Object[] { 1, 2 });        System.out.println(result); // 此時result是Integer類型                //調用第二個方法        Method echoMethod = classType.getDeclaredMethod("echo", new Class[]{String.class});        Object result2 = echoMethod.invoke(invokeTester, new Object[]{"Tom"});        System.out.println(result2);    }}

 

 

產生對象

 

  若想通過類的不帶參數的構造方法來產生對象,我們有兩種方式:

  1.先獲得Class對象,然後通過該Class對象的newInstance()方法直接產生即可:

     Class<?> classType = String.class;     Object obj = classType.newInstance();

 

  2.先獲得Class對象,然後通過該對象獲得對應的Constructor對象,再通過該Constructor對象的newInstance()方法產生

  (其中Customer是一個自訂的類,有一個無參數的構造方法,也有帶參數的構造方法):

    Class<?> classType = Customer.class;    // 獲得Constructor對象,此處擷取第一個無參數的構造方法的    Constructor cons = classType.getConstructor(new Class[] {});    // 通過構造方法來產生一個對象    Object obj = cons.newInstance(new Object[] {});

 

  若想通過類的帶參數的構造方法產生對象,只能使用下面這一種方式:

  (Customer為一個自訂的類,有無參數的構造方法,也有一個帶參數的構造方法,傳入字串和整型)

    Class<?> classType = Customer.class;    Constructor cons2 = classType.getConstructor(new Class[] {String.class, int.class});    Object obj2 = cons2.newInstance(new Object[] {"ZhangSan",20});

  可以看出調用構造方法產生對象的方法和調用一般方法的類似,不同的是從Class對象擷取Constructor對象時不需要指定名字,而擷取Method對象時需要指定名字。

 

     原文轉至與http://www.cnblogs.com/mengdd/archive/2013/01/26/2877972.html

Java反射(Reflection)

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.