1. 程式人生 > >Java中反射機制詳解

Java中反射機制詳解

turn face instance java struct () 分享 2.6 一個

    序言

      在學習java基礎時,由於學的不紮實,講的實用性不強,就覺得沒用,很多重要的知識就那樣一筆帶過了,像這個馬上要講的反射機制一樣,當時學的時候就忽略了,到後來學習的知識中,很多東西動不動就用反射,所以回過頭來把這個給重新補一下,自己欠下的債,遲早是要還的。

                                      ---WH

一、什麽是反射?

    在運行狀態中,對於任意一個類,都能夠獲取到這個類的所有屬性和方法,對於任意一個對象,都能夠調用它的任意一個方法和屬性(包括私有的方法和屬性),這種動態獲取的信息以及動態調用對象的方法的功能就稱為java語言的反射機制。通俗點講,通過反射,該類對我們來說是完全透明的,想要獲取任何東西都可以。

    想要使用反射機制,就必須要先獲取到該類的字節碼文件對象(.class),通過字節碼文件對象,就能夠通過該類中的方法獲取到我們想要的所有信息(方法,屬性,類名,父類名,實現的所有接口等等),每一個類對應著一個字節碼文件也就對應著一個Class類型的對象,也就是字節碼文件對象。

    獲取字節碼文件對象的三種方式。

       1、Class clazz1 = Class.forName("全限定類名");  //通過Class類中的靜態方法forName,直接獲取到一個類的字節碼文件對象,此時該類還是源文件階段,並沒有變為字節碼文件。

       2、Class clazz2 = Person.class;    //當類被加載成.class文件時,此時Person類變成了.class,在獲取該字節碼文件對象,也就是獲取自己, 該類處於字節碼階段。

       3、Class clazz3 = p.getClass();    //通過類的實例獲取該類的字節碼文件對象,該類處於創建對象階段 

    有了字節碼文件對象才能獲得類中所有的信息,我們在使用反射獲取信息時,也要考慮使用上面哪種方式獲取字節碼對象合理,視不同情況而定。下面介紹Class類的功能。

二、反射機制能夠獲取哪些信息?Class類的API詳解。

    2.1、通過字節碼對象創建實例對象

         技術分享

    2.2、獲取指定構造器方法。constructor 如果沒有無參構造,只有有參構造如何創建實例呢?看下面

         技術分享

      總結上面創建實例對象:Class類的newInstance()方法是使用該類無參的構造函數創建對象, 如果一個類沒有無參的構造函數, 就不能這樣創建了,可以調用Class類的                             getConstructor(String.class,int.class)方法獲取一個指定的構造函數然後再調用Constructor類的newInstance("張三",20)方法創建對象

      獲取全部構造方法  

         技術分享     

    2.3、獲取成員變量並使用  Field對象

         獲取指定成員變量

         技術分享 

         Class.getField(String)方法可以獲取類中的指定字段(可見的), 如果是私有的可以用getDeclaedField("name")方法獲取,通過set(obj, "李四")方法可以設置指定對象上該字段的值, 如果是私有的需要先調用setAccessible(true)設置訪問權限,用獲取的指定的字段調用get(obj)可以獲取指定對象中該字段的值

        獲取全部成員變量

        技術分享

    2.4、獲得方法並使用  Method

         技術分享 

        Class.getMethod(String, Class...) 和 Class.getDeclaredMethod(String, Class...)方法可以獲取類中的指定方法,    

          如果為私有方法,則需要打開一個權限。setAccessible(true);

        用invoke(Object, Object...)可以調用該方法,

        跟上面同理,也能一次性獲得所有的方法

         技術分享 

               

    2.5、獲得該類的所有接口

         Class[] getInterfaces():確定此對象所表示的類或接口實現的接口

         返回值:接口的字節碼文件對象的數組

    2.6、獲取指定資源的輸入流

         InputStream getResourceAsStream(String name)  

         return:一個 InputStream 對象;如果找不到帶有該名稱的資源,則返回 null

         參數:所需資源的名稱,如果以"/"開始,則絕對資源名為"/"後面的一部分。

    2.7、動態代理的概述和實現

       動態代理:一種設計模式,其非常簡單,很容易理解,你自己可以做這件事,但是覺得自己做非常麻煩或者不方便,所以就叫一個另一個人(代理)來幫你做這個事情,而你就不用管了,這就是動態代理。舉個例子,買火車票叫人代買。

       在程序運行過程中產生的這個對象,而程序運行過程中產生對象其實就是我們剛才反射講解的內容,所以,動態代理其實就是通過反射來生成一個代理

       在Java中java.lang.reflect包下提供了一個Proxy類和一個InvocationHandler接口,通過使用這個類和接口就可以生成動態代理對象。JDK提供的代理只能針對接口做代理。我們有更強大的代理cglib,Proxy類中的方法創建動態代理類對象 

        分三步,但是註意JDK提供的代理正能針對接口做代理,也就是下面的第二步返回的必須要是一個接口。

       1、new出代理對象,通過實現InvacationHandler接口,然後new出代理對象來。

       2、通過Proxy類中的靜態方法newProxyInstance,來將代理對象假裝成那個被代理的對象,也就是如果叫人幫我們代買火車票一樣,那個代理就假裝成我們自己本人

       3、執行方法,代理成功

          將代理對象中的內容進行實現

          技術分享     

          技術分享   

          技術分享

  

        1、2、3步

          技術分享

        註意newProxyInstance的三個參數,第一個,類加載器,第二個被代理對象的接口,第三個代理對象。  

       

    2.8、還有很多方法,比如獲得類加載器,等等

       具體還需要別的,就通過查看API文檔來解決。

三、反射機制的應用實例

    3.1、利用反射,在泛型為int的arryaList集合中存放一個String類型的對象

       原理:集合中的泛型只在編譯器有效,而到了運行期,泛型則會失效,

         技術分享

   3.2、利用反射,簡化編寫Servlet的個數。

        什麽意思呢?每當我們寫一個功能時,就需要寫一個對應的Servlet,導致最後Servlet有很多,自己都看不過來,所以對其進行了優化,兩種方式,

        3.2.1、每次從頁面傳過來一個參數,method="xxx"; 然後編寫一個Servlet,獲得其參數method的值,進行判斷,如果是add,則調用add方法,如果是delete,則調用delete方法,這樣就可以寫在一個servlet中實現所有的功能了。 

        技術分享

      3.2.2、利用反射

        編寫一個BaseServlet繼承HttpServlet,這是一個通用的BaseServlet。需要明白servlet的生命周期

        技術分享

        編寫具體實現的方法servlet類。

        MySerlvet001 extends BaseServlet

        技術分享

        

        解釋:需要明白servlet的生命周期,也就是service方法,因為是servlet,所以在訪問的時候,會經過service方法,而子類MyServlet001中並沒有,所以就到父類BaseServlet中找,發現有,然後獲取參數即知道了需要調用什麽方法,因為方法的編寫都在子類中,所以通過反射,獲取到子類中對應的方法並運行,其中需要註意的是this這個參數在BaseServlet中的用法。需要理解它。才能理解我們這個程序。

四、總結

      反射基本上就這樣講完了,其實就是對其一些api進行講解,不懂的就查看API,重要的思想,就要在實際中遇到了才能得到更好的理解。先這樣過一遍,零零碎碎的知識。

   

Java中反射機制詳解