乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

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

       oldzhoua 2019-04-10

      一、什么是反射?

          在運(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í)例呢?

      // 獲取字節(jié)碼文件Class clazz = Class.forName('com.demo.User');// 先獲取有參構(gòu)造器,parameterTypes:表示參數(shù)列表,有多少寫多少,也可以不寫,不寫調(diào)用的就是無參構(gòu)造函數(shù)Construtor constructor = clazz.getConstructor(int.class, String.class);// 通過構(gòu)造器來實(shí)例化對象,將實(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é)碼對象。  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í)例對象User user = (User) clazz.newInstance();// 成員變量為非私有變量,使用getField(name)獲??;通過name來獲取指定成員變量Field field = clazz.getField('name');// 成員變量為私有屬性,獲得其屬性對象后,還要讓其打開可見權(quán)限Field field1 = clazz.getDeclaredField('id');field1.setAccessible(true);// 對其變量進(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)限打開  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類型,沒有則什么都不填,比如參數(shù)為string,則填String.class*/Method method = clazz.getMethod('eat');// 調(diào)用方法/*** method.invoke(obj, args)* obj: 方法的對象* args: 實(shí)際的參數(shù)值,沒有則不填*/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():確定此對象所表示的類或接口實(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 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è)被代理對象的接口,第三個(gè)代理對象?! ?/p>

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

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

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

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

         原理:集合中的泛型只在編譯器有效,而到了運(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_發(fā)中,反射用到的比較少,或者即使碰到也不知道這里是用反射實(shí)現(xiàn)的,了解反射的實(shí)現(xiàn)更利于我們寫代碼,這篇文章只介紹了反射的基本知識,更多使用場景在實(shí)際開發(fā)中遇到會(huì)更加好理解。

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

        0條評論

        發(fā)表

        請遵守用戶 評論公約

        類似文章 更多