原文地址:https://www.cnblogs.com/whgk/p/6122036.html
一、什么是反射?
在運行狀態中,對於任意一個類,都能夠獲取到這個類的所有屬性和方法,對於任意一個對象,都能夠調用它的任意一個方法和屬性(包括私有的方法和屬性),這種動態獲取的信息以及動態調用對象的方法的功能就稱為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中的用法。需要理解它。才能理解我們這個程序。