小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

Java中的反射機(jī)制詳解

 oldzhoua 2019-04-10

一、什么是反射?

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

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

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

1 Class clazz1 = Class.forName('全限定類名')

通過(guò)Class類中的靜態(tài)方法forName,直接獲取到一個(gè)類的字節(jié)碼文件對(duì)象,此時(shí)該類還是源文件階段,并沒(méi)有變?yōu)樽止?jié)碼文件。

2 Class clazz2  = Person.class

當(dāng)類被加載成.class文件時(shí),此時(shí)Person類變成了.class,在獲取該字節(jié)碼文件對(duì)象,也就是獲取自己, 該類處于字節(jié)碼階段。

3 Class clazz3 = p.getClass()

通過(guò)類的實(shí)例獲取該類的字節(jié)碼文件對(duì)象,該類處于創(chuàng)建對(duì)象階段 

有了字節(jié)碼文件對(duì)象才能獲得類中所有的信息,我們?cè)谑褂梅瓷浍@取信息時(shí),也要考慮使用上面哪種方式獲取字節(jié)碼對(duì)象合理,視不同情況而定。下面介紹Class類的功能。

二、反射機(jī)制能夠獲取哪些信息

2.1 通過(guò)反射獲取類實(shí)例信息

//獲取字節(jié)碼文件Class clazz = Class.forName('com.demo.user');//創(chuàng)建User實(shí)例,這里是通過(guò)User的無(wú)參構(gòu)造函數(shù)來(lái)創(chuàng)建的User user = (User) clazz1.newInstance();

2.2 獲取指定構(gòu)造器方法

2.1說(shuō)明了通過(guò)無(wú)參構(gòu)造器創(chuàng)建實(shí)例的方法,那如果只有有參的構(gòu)造器該如何創(chuàng)建實(shí)例呢?

// 獲取字節(jié)碼文件Class clazz = Class.forName('com.demo.User');// 先獲取有參構(gòu)造器,parameterTypes:表示參數(shù)列表,有多少寫(xiě)多少,也可以不寫(xiě),不寫(xiě)調(diào)用的就是無(wú)參構(gòu)造函數(shù)Construtor constructor = clazz.getConstructor(int.class, String.class);// 通過(guò)構(gòu)造器來(lái)實(shí)例化對(duì)象,將實(shí)際的參數(shù)傳進(jìn)去User user = (User) constructor.newInstance(18, '寶寶');

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é)碼對(duì)象。  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)、獲取指定成員變量

//獲取字節(jié)碼文件Class clazz = Class.forName('com.demo.User');//獲取實(shí)例對(duì)象User user = (User) clazz.newInstance();// 成員變量為非私有變量,使用getField(name)獲??;通過(guò)name來(lái)獲取指定成員變量Field field = clazz.getField('name');// 成員變量為私有屬性,獲得其屬性對(duì)象后,還要讓其打開(kāi)可見(jiàn)權(quán)限Field field1 = clazz.getDeclaredField('id');field1.setAccessible(true);// 對(duì)其變量進(jìn)行賦值操作field1.setInt(user, 5);// 獲取成員變量得值System.out.println(field.getInt(user));

(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)限打開(kāi)  System.out.println(fields[i].get(user)); //獲取成員變量的值}

2.5 獲得方法并使用 

Class clazz = Class.forName('com.demo.User');User user = (User) clazz.newInstance();// 不帶參數(shù)的方法, eat為不帶參數(shù)的public方法/***clazz.getMethod(name, parameterTypes)* name: 方法名* parameterTypes: 方法的參數(shù)類型的Class類型,沒(méi)有則什么都不填,比如參數(shù)為string,則填String.class*/Method method = clazz.getMethod('eat');// 調(diào)用方法/*** method.invoke(obj, args)* obj: 方法的對(duì)象* args: 實(shí)際的參數(shù)值,沒(méi)有則不填*/method.invoke(user);
// 帶參數(shù)的方法,sing為帶一個(gè)String類型參數(shù)的方法Method method1 = clazz.getMethod('sing', String.class);method1.invoke(user, '小明');
// 獲取私有的方法,和獲取私有屬性一樣,say為私有方法Method method2 = clazz.getDeclaredMethod('say');methods.setAccessible(true);method2.invoke(user);

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():確定此對(duì)象所表示的類或接口實(shí)現(xiàn)的接口

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

2.8 獲取指定資源的輸入流

 InputStream getResourceAsStream(String name)  

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

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

2.9 動(dòng)態(tài)代理的概述和實(shí)現(xiàn)

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

  在程序運(yùn)行過(guò)程中產(chǎn)生的這個(gè)對(duì)象,而程序運(yùn)行過(guò)程中產(chǎn)生對(duì)象其實(shí)就是我們剛才反射講解的內(nèi)容,所以,動(dòng)態(tài)代理其實(shí)就是通過(guò)反射來(lái)生成一個(gè)代理

  在Java中java.lang.reflect包下提供了一個(gè)Proxy類和一個(gè)InvocationHandler接口,通過(guò)使用這個(gè)類和接口就可以生成動(dòng)態(tài)代理對(duì)象。JDK提供的代理只能針對(duì)接口做代理。我們有更強(qiáng)大的代理cglib,Proxy類中的方法創(chuàng)建動(dòng)態(tài)代理類對(duì)象分三步,但是注意JDK提供的代理只能針對(duì)接口做代理,也就是下面的第二步返回的必須要是一個(gè)接口。

  1、new出代理對(duì)象,通過(guò)實(shí)現(xiàn)InvacationHandler接口,然后new出代理對(duì)象來(lái)。

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

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

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

public class MyInvocationHandler implements InvocationHandler{  private Object target;    public MyInvocationHandler(Object target) {    this.target = target;  }    @Override  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {    System.out.println('權(quán)限校驗(yàn)');    method.invoke(target, args);    System.out.println('日志打印');    return null;  }}
public interface Student{
public void login(); public void submit();}
@Overridepublic void login(){  System.out.println('登錄');}
@Overridepublic void submit() {  System.out.println('提交');}
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è)被代理對(duì)象的接口,第三個(gè)代理對(duì)象?! ?/p>

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

  具體還需要?jiǎng)e的,就通過(guò)查看API文檔來(lái)解決。

三、反射機(jī)制的應(yīng)用是咧

3.1 利用反射,在泛型為int的arryaList集合中存放一個(gè)String類型的對(duì)象

   原理:集合中的泛型只在編譯器有效,而到了運(yùn)行期,泛型則會(huì)失效

List<Integer> list = new ArrayList<Integer>;list.add(4);list.add(5);Class clazz = list.getClass();Method method = clazz.getMethod('add', Object.class);method.invoke(list, 'ddd');System.out.println(list);

四、總結(jié)

在我們?nèi)粘i_(kāi)發(fā)中,反射用到的比較少,或者即使碰到也不知道這里是用反射實(shí)現(xiàn)的,了解反射的實(shí)現(xiàn)更利于我們寫(xiě)代碼,這篇文章只介紹了反射的基本知識(shí),更多使用場(chǎng)景在實(shí)際開(kāi)發(fā)中遇到會(huì)更加好理解。

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買(mǎi)等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多