天天看點

Java反射機制深度剖析

版權聲明:本文為部落客原創文章,轉載請注明出處,歡迎交流學習!

      Java反射機制是Java語言中一種很重要的機制,可能在工作中用到的機會不多,但是在很多架構中都有用到這種機制。我們知道Java是一門靜态語言,在程式編譯時變量的資料類型都已經确定,那麼在Java運作時環境中,對于任意一個類,我們能否知道這個類有哪些屬性和方法?對于任意一個對象,能否調用它的任意一個方法?答案是肯定的。這種動态擷取類的資訊以及動态調用對象的方法的功能來自于Java的反射機制(Reflection)。

      1、Java反射機制提供的功能

      主要提供了以下幾個功能:

      1)在運作時判斷任意一個對象所屬的類;

      2)在運作時構造任意一個類的對象;

      3)在運作時判斷任意一個類所具有的成員變量和方法;

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

      反射讓Java具有了動态的特性,這種機制允許程式在運作時透過Reflection API擷取任意一個已知名稱的類的内部資訊,包括成員變量(fields)、方法(methods)、實作的接口(interfaces)、Java語言修飾符(modifiers)以及它的父類(superclass)等等,并可在運作時改變成員變量的内容或調用方法。

      2、Java Reflection API

      在JDK中,提供了以下類來實作Java反射機制,這些類都位于java.lang.reflect包下:

      Class類:代表一個類(注意:Class類位于java.lang包下);

      Field類:代表類的成員變量;

      Method類:代表類的方法;

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

      Array類:提供了動态建立數組,以及通路數組的元素的靜态方法。

      通過API提供的這些類裡的方法,我們可以動态擷取想要的類的内部資訊。

      3、擷取類的Class對象

      Class類的執行個體表示正在運作的Java程式中的類和接口,每一個類都有對應的Class對象,不管一個類生成了多少個對象,這些對象都對應記憶體裡的同一個Class對象。Class類沒有public的構造方法,Class對象是在加載類時由Java虛拟機自動建構的。

      有以下幾種方式來擷取一個類的Class對象:

      1)Class類提供的靜态方法:forName(String className),參數className表示所需類的完全限定名。     

      2)運用.class文法     

      3)Object類提供的方法:getClass()     

      4、擷取類的Field(成員變量)對象

      類的每一個成員變量都對應一個Field對象,Class類提供了以下方法來擷取類的成員變量對應的Field對象:

      1)Field getDeclaredField(String name):根據傳入的變量名稱傳回此Class對象所表示的類或接口中聲明的變量對應的Field對象。

      2)Field[] getDeclaredFields():傳回一個Field類型的數組,包含此Class對象所表示的類或接口中聲明的所有變量的Field對象。

      3)Field getField(String name):根據傳入的變量名傳回一個Field對象,注意與getDeclaredField(String name)不同的是,此方法傳回的是public變量對應的Field對象。

      4)Field[] getFields():傳回一個Field類型的數組,注意與Field[] getDeclaredFields()方法不同的是,此方法傳回的是所有public變量對應的Field對象。

      代碼示例:

      輸出結果:

Java反射機制深度剖析

      從結果輸出可以看出getDeclaredFields()與getFields()的差別:getDeclaredFields()傳回的是所有屬性的Field對象;而getFields()傳回的是聲明為public的屬性的Field對象。

      5、擷取類的Method對象

      類中的每一個方法都對應一個Method對象,Class類提供了以下方法來擷取類中的方法對應的Method對象:

      1)Method getDeclaredMethod(String name, Class<?>... parameterTypes):傳回一個Method對象,參數name表示方法名,可變參數parameterTypes是一個Class對象的數組,代表方法的參數的Class類型;

      2)Method[] getDeclaredMethods():傳回Method對象的一個數組,這些對象反映此Class對象所表示的類或接口聲明的所有方法,包括公共、保護、預設通路和私有方法,但不包括繼承的方法;

      3)Method getMethod(String name, Class<?>... parameterTypes):傳回一個Method對象,注意和此Method對象對應的方法是公共(public)方法;

      4)Method[] getMethods():傳回一個Method數組,這些對象反映此Class對象所表示的類或接口中聲明的公共(public)方法(也包括父類或父接口中聲明的public方法)。

      代碼示例:     

Java反射機制深度剖析

      6、用反射機制調用對象的方法

      Java反射機制可以在運作時動态調用類中的方法,Java Reflection API提供了我們所需的方法來完成動态調用。要想調用類中的方法首先要建立一個對象,我們通過類的Class對象來建立它所代表的類的執行個體,通過Class對象我們還能獲得類中聲明的方法的Method對象,Method類提供了Invoke方法來調用此Method對象所表示的方法。反射機制調用方法代碼示例如下:   

      7、用反射機制調用類的私有方法

      我們知道正常情況下一個類的私有方法隻允許這個類本身來調用,但使用反射機制能打破這種通路限制,讓其他的類也能調用這個類的私有的方法。這種場景在實際開發中很少用到,Java也不提倡這種用法。代碼示例如下:  

      Method、Field、Constructor類有一個共同的父類AccessibleObject類,它提供了将反射的對象标記為在使用時取消預設Java語言通路控制檢查的能力。在上面的代碼中,我們在反射對象Method中設定accessible标志,它允許程式以某種通常禁止的方式來操作對象。

      8、用反射機制操作類的私有變量

      與前面調用類的私有方法類似,通過反射我們還能操作類的私有變量,代碼示例如下:   

      以上這些内容,我介紹了Java反射機制的中涉及的主要的幾個類以及這些類的基本用法,這些類中還有很多的方法,大家可以通過檢視API進行了解,用法都很簡單。Java反射機制在很多架構的底層實作中有用到,還有一種很重要的設計模式也用到了反射,那就是代理模式中的動态代理,了解了動态代理模式的思想對我們研究架構有很大幫助,我會在後面的部落格中介紹這些内容,歡迎大家共同探讨。