序言

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

                                      ---WH

一、什么是反射?

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

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

    獲取字節(jié)碼文件對象的三種方式。

       1、Class clazz1 = Class.forName("全限定類名");  //通過Class類中的靜態(tài)方法forName,直接獲取到一個類的字節(jié)碼文件對象,此時該類還是源文件階段,并沒有變?yōu)樽止?jié)碼文件。

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

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

 

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

 

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

    2.1、通過字節(jié)碼對象創(chuàng)建實例對象

         萬碼學堂,電腦培訓,計算機培訓,Java培訓,JavaEE開發(fā)培訓,青島軟件培訓,軟件工程師培訓

    2.2、獲取指定構(gòu)造器方法。constructor 如果沒有無參構(gòu)造,只有有參構(gòu)造如何創(chuàng)建實例呢?看下面

         萬碼學堂,電腦培訓,計算機培訓,Java培訓,JavaEE開發(fā)培訓,青島軟件培訓,軟件工程師培訓

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

      獲取全部構(gòu)造方法  

         萬碼學堂,電腦培訓,計算機培訓,Java培訓,JavaEE開發(fā)培訓,青島軟件培訓,軟件工程師培訓     

 

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

         獲取指定成員變量

         萬碼學堂,電腦培訓,計算機培訓,Java培訓,JavaEE開發(fā)培訓,青島軟件培訓,軟件工程師培訓 

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

        獲取全部成員變量

        萬碼學堂,電腦培訓,計算機培訓,Java培訓,JavaEE開發(fā)培訓,青島軟件培訓,軟件工程師培訓

 

    2.4、獲得方法并使用  Method

         萬碼學堂,電腦培訓,計算機培訓,Java培訓,JavaEE開發(fā)培訓,青島軟件培訓,軟件工程師培訓 

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

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

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

 

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

         萬碼學堂,電腦培訓,計算機培訓,Java培訓,JavaEE開發(fā)培訓,青島軟件培訓,軟件工程師培訓 

               

    2.5、獲得該類的所有接口

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

         返回值:接口的字節(jié)碼文件對象的數(shù)組

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

         InputStream getResourceAsStream(String name)  

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

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

 

    2.7、動態(tài)代理的概述和實現(xiàn)

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

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

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

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

       1、new出代理對象,通過實現(xiàn)InvacationHandler接口,然后new出代理對象來。

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

       3、執(zhí)行方法,代理成功

          將代理對象中的內(nèi)容進行實現(xiàn)

          萬碼學堂,電腦培訓,計算機培訓,Java培訓,JavaEE開發(fā)培訓,青島軟件培訓,軟件工程師培訓     

          萬碼學堂,電腦培訓,計算機培訓,Java培訓,JavaEE開發(fā)培訓,青島軟件培訓,軟件工程師培訓   

          萬碼學堂,電腦培訓,計算機培訓,Java培訓,JavaEE開發(fā)培訓,青島軟件培訓,軟件工程師培訓

  

        1、2、3步

          萬碼學堂,電腦培訓,計算機培訓,Java培訓,JavaEE開發(fā)培訓,青島軟件培訓,軟件工程師培訓

        注意newProxyInstance的三個參數(shù),第一個,類加載器,第二個被代理對象的接口,第三個代理對象?! ?/p>

 

 

       

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

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

 

 

三、反射機制的應(yīng)用實例

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

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

         萬碼學堂,電腦培訓,計算機培訓,Java培訓,JavaEE開發(fā)培訓,青島軟件培訓,軟件工程師培訓

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

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

        3.2.1、每次從頁面?zhèn)鬟^來一個參數(shù),method="xxx"; 然后編寫一個Servlet,獲得其參數(shù)method的值,進行判斷,如果是add,則調(diào)用add方法,如果是delete,則調(diào)用delete方法,這樣就可以寫在一個servlet中實現(xiàn)所有的功能了?!?/p>

        萬碼學堂,電腦培訓,計算機培訓,Java培訓,JavaEE開發(fā)培訓,青島軟件培訓,軟件工程師培訓

 

      3.2.2、利用反射

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

        萬碼學堂,電腦培訓,計算機培訓,Java培訓,JavaEE開發(fā)培訓,青島軟件培訓,軟件工程師培訓

        編寫具體實現(xiàn)的方法servlet類。

        MySerlvet001 extends BaseServlet

        萬碼學堂,電腦培訓,計算機培訓,Java培訓,JavaEE開發(fā)培訓,青島軟件培訓,軟件工程師培訓

        

        解釋:需要明白servlet的生命周期,也就是service方法,因為是servlet,所以在訪問的時候,會經(jīng)過service方法,而子類MyServlet001中并沒有,所以就到父類BaseServlet中找,發(fā)現(xiàn)有,然后獲取參數(shù)即知道了需要調(diào)用什么方法,因為方法的編寫都在子類中,所以通過反射,獲取到子類中對應(yīng)的方法并運行,其中需要注意的是this這個參數(shù)在BaseServlet中的用法。需要理解它。才能理解我們這個程序。

 

 

 

四、總結(jié)

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