一、什么是反射? 在運(yùn)行狀態(tài)中,對于任意一個(gè)類,都能夠獲取到這個(gè)類的所有屬性和方法,對于任意一個(gè)對象,都能夠調(diào)用它的任意一個(gè)方法和屬性(包括私有的方法和屬性),這種動(dòng)態(tài)獲取的信息以及動(dòng)態(tài)調(diào)用對象的方法的功能就稱為java語言的反射機(jī)制。通俗點(diǎn)講,通過反射,該類對我們來說是完全透明的,想要獲取任何東西都可以。 想要使用反射機(jī)制,就必須要先獲取到該類的字節(jié)碼文件對象(.class),通過字節(jié)碼文件對象,就能夠通過該類中的方法獲取到我們想要的所有信息(方法,屬性,類名,父類名,實(shí)現(xiàn)的所有接口等等),每一個(gè)類對應(yīng)著一個(gè)字節(jié)碼文件也就對應(yīng)著一個(gè)Class類型的對象,也就是字節(jié)碼文件對象。 獲取字節(jié)碼文件對象的三種方式。 1 Class clazz1 = Class.forName('全限定類名') 通過Class類中的靜態(tài)方法forName,直接獲取到一個(gè)類的字節(jié)碼文件對象,此時(shí)該類還是源文件階段,并沒有變?yōu)樽止?jié)碼文件。 2 Class clazz2 = Person.class 當(dāng)類被加載成.class文件時(shí),此時(shí)Person類變成了.class,在獲取該字節(jié)碼文件對象,也就是獲取自己, 該類處于字節(jié)碼階段。 3 Class clazz3 = p.getClass() 通過類的實(shí)例獲取該類的字節(jié)碼文件對象,該類處于創(chuàng)建對象階段 有了字節(jié)碼文件對象才能獲得類中所有的信息,我們在使用反射獲取信息時(shí),也要考慮使用上面哪種方式獲取字節(jié)碼對象合理,視不同情況而定。下面介紹Class類的功能。 二、反射機(jī)制能夠獲取哪些信息 2.1 通過反射獲取類實(shí)例信息 //獲取字節(jié)碼文件 Class clazz = Class.forName('com.demo.user'); //創(chuàng)建User實(shí)例,這里是通過User的無參構(gòu)造函數(shù)來創(chuàng)建的 User user = (User) clazz1.newInstance(); 2.2 獲取指定構(gòu)造器方法 2.1說明了通過無參構(gòu)造器創(chuàng)建實(shí)例的方法,那如果只有有參的構(gòu)造器該如何創(chuàng)建實(shí)例呢?
2.3 獲取全部構(gòu)造方法 Class clazz = Class.forName('com.demo.User'); // 獲取所有構(gòu)造方法 Constructor[] constructors = clazz.getConstructors(); // 遍歷所有構(gòu)造方法 for(int i = 0; i < constructors.length; i++) { // 獲取每個(gè)構(gòu)造函數(shù)中得參數(shù)類型字節(jié)碼對象。 Class[] parameterTypes = constructors[i].getParameterTypes(); System.out.println('第'+i+'個(gè)構(gòu)造函數(shù)'); for(int j = 0; j < parameterTypes.length; j++) { //獲取構(gòu)造函數(shù)中參數(shù)類型 System.out.print(parameterTypes[j].getName()+','); } } 2.4 獲取類得所有成員變量 (1)、獲取指定成員變量
(2)、獲取全部成員變量 Class clazz = Class.forName('com.demo.User'); User user = (User) clazz.newInstance(); user.setId(13); // 賦值操作 user.setName('寶寶'); // 賦值操作 Field[] fields = clazz.getDeclaredFields(); // 將私有的屬性也一并獲得 for(int i = 0; i<fields.length; i++) { fields[i].setAccessible(true); // 將屬性(尤指私有屬性)的權(quán)限打開 System.out.println(fields[i].get(user)); //獲取成員變量的值 } 2.5 獲得方法并使用
2.6 獲取所有方法 Method[] methods = clazz.getDeclaredMethods(); User user = (User) clazz.newInstance(); for(Method method : methods) { method.setAccessible(true); System.out.ptintln(method.getName()); // 獲得方法的參數(shù),又回到了之前的代碼 Class<?> parameterTypes = method.getParameterTypes(); for(int j=0; j<parameterTypes.length; j++) { // 獲取構(gòu)造函數(shù)中的參數(shù)類型 System.out.print(parameterTypes[j].getName()+','); } } 2.7 獲得該類的所有接口 Class[] getInterfaces():確定此對象所表示的類或接口實(shí)現(xiàn)的接口 返回值:接口的字節(jié)碼文件對象的數(shù)組 2.8 獲取指定資源的輸入流 InputStream getResourceAsStream(String name) return:一個(gè) InputStream 對象;如果找不到帶有該名稱的資源,則返回 null 參數(shù):所需資源的名稱,如果以'/'開始,則絕對資源名為'/'后面的一部分。 2.9 動(dòng)態(tài)代理的概述和實(shí)現(xiàn) 動(dòng)態(tài)代理:一種設(shè)計(jì)模式,其非常簡單,很容易理解,你自己可以做這件事,但是覺得自己做非常麻煩或者不方便,所以就叫一個(gè)另一個(gè)人(代理)來幫你做這個(gè)事情,而你就不用管了,這就是動(dòng)態(tài)代理。舉個(gè)例子,買火車票叫人代買。 在程序運(yùn)行過程中產(chǎn)生的這個(gè)對象,而程序運(yùn)行過程中產(chǎn)生對象其實(shí)就是我們剛才反射講解的內(nèi)容,所以,動(dòng)態(tài)代理其實(shí)就是通過反射來生成一個(gè)代理 在Java中java.lang.reflect包下提供了一個(gè)Proxy類和一個(gè)InvocationHandler接口,通過使用這個(gè)類和接口就可以生成動(dòng)態(tài)代理對象。JDK提供的代理只能針對接口做代理。我們有更強(qiáng)大的代理cglib,Proxy類中的方法創(chuàng)建動(dòng)態(tài)代理類對象分三步,但是注意JDK提供的代理只能針對接口做代理,也就是下面的第二步返回的必須要是一個(gè)接口。 1、new出代理對象,通過實(shí)現(xiàn)InvacationHandler接口,然后new出代理對象來。 2、通過Proxy類中的靜態(tài)方法newProxyInstance,來將代理對象假裝成那個(gè)被代理的對象,也就是如果叫人幫我們代買火車票一樣,那個(gè)代理就假裝成我們自己本人 3、執(zhí)行方法,代理成功 將代理對象中的內(nèi)容進(jìn)行實(shí)現(xiàn)
public interface Student{
public void login(); public void submit(); }
MyInvocationHandler m = new MyInvocationHandler(si); Student s = (Student) Proxy.newProxyInstance(si.getClass().getClassLoader(), si.getClass().getInterfaces(), m); s.login(); s.submit(); 注意newProxyInstance的三個(gè)參數(shù),第一個(gè),類加載器,第二個(gè)被代理對象的接口,第三個(gè)代理對象?! ?/p> 2.10 還有很多方法,比如獲得類加載器,等等 具體還需要?jiǎng)e的,就通過查看API文檔來解決。 三、反射機(jī)制的應(yīng)用是咧 3.1 利用反射,在泛型為int的arryaList集合中存放一個(gè)String類型的對象 原理:集合中的泛型只在編譯器有效,而到了運(yùn)行期,泛型則會(huì)失效
四、總結(jié) 在我們?nèi)粘i_發(fā)中,反射用到的比較少,或者即使碰到也不知道這里是用反射實(shí)現(xiàn)的,了解反射的實(shí)現(xiàn)更利于我們寫代碼,這篇文章只介紹了反射的基本知識,更多使用場景在實(shí)際開發(fā)中遇到會(huì)更加好理解。 |
|