java反射與動態代理的理解

来源:https://www.cnblogs.com/jacksontao/archive/2018/03/12/8552357.html
-Advertisement-
Play Games

一、什麼是反射機制? 反射的官方定義是這樣的:在運行狀態中,對於任意的一個類,都能夠知道這個類的所有屬性和方法,對任意一個對象都能夠通過反射機制調用一個類的任意方法,這種動態獲取類信息及動態調用類對象方法的功能稱為java的反射機制。 講的通俗一點的話就是,對於jvm來說,.java文件必須要先編譯 ...


一、什麼是反射機制?

  反射的官方定義是這樣的:在運行狀態中,對於任意的一個類,都能夠知道這個類的所有屬性和方法,對任意一個對象都能夠通過反射機制調用一個類的任意方法,這種動態獲取類信息及動態調用類對象方法的功能稱為java的反射機制。  

  講的通俗一點的話就是,對於jvm來說,.java文件必須要先編譯為.class文件才能夠被jvm執行,所以在編譯為.class文件的過程中,對象的類型都會被指定好,比如說 User user。那麼如果說我想在代碼運行的過程中獲取到對象的類型呢?或者說程式在運行過程中如何載入一個特定的類呢?這就涉及到了java的反射機制了,反射提供了一套能夠讓我們在代碼運行時也能獲取到類型屬性的方法。

二、反射的使用

  jdk提供了三種方式獲取一個對象的Class,就User user來說

  1.user.getClass(),這個是Object類裡面的方法

  2.User.Class屬性,任何的數據類型,基本數據類型或者抽象數據類型,都可以通過這種方式獲取類

  3.Class.forName(""),Class類提供了這樣一個方法,讓我們通過類名來獲取到對象類

  這三種方法用的最多的就是第三種,那麼獲取到類之後,Class類提供了很多獲取類屬性,方法,構造方法的api。

  1.獲取所有的屬性

//獲取整個類  
            Class c = Class.forName("java.lang.Integer");  
              //獲取所有的屬性?  
            Field[] fs = c.getDeclaredFields();  
       
                   //定義可變長的字元串,用來存儲屬性  
            StringBuffer sb = new StringBuffer();  
            //通過追加的方法,將每個屬性拼接到此字元串中  
            //最外邊的public定義  
            sb.append(Modifier.toString(c.getModifiers()) + " class " + c.getSimpleName() +"{\n");  
            //裡邊的每一個屬性  
            for(Field field:fs){  
                sb.append("\t");//空格  
                sb.append(Modifier.toString(field.getModifiers())+" ");//獲得屬性的修飾符,例如public,static等等  
                sb.append(field.getType().getSimpleName() + " ");//屬性的類型的名字  
                sb.append(field.getName()+";\n");//屬性的名字+回車  
            }  
      
            sb.append("}");  
      
            System.out.println(sb);  

 

  2.獲取特定的屬性

 //獲取類  
    Class c = Class.forName("User");  
    //獲取id屬性  
    Field idF = c.getDeclaredField("id");  
    //實例化這個類賦給o  
    Object o = c.newInstance();  
    //打破封裝  
    idF.setAccessible(true); //使用反射機制可以打破封裝性,導致了java對象的屬性不安全。  
    //給o對象的id屬性賦值"110"  
    idF.set(o, "110"); //set  
    //get  
    System.out.println(idF.get(o)); 

 

  3.獲取方法

getDeclaredMethods()    獲取所有的方法

getReturnType()    獲得方法的放回類型

getParameterTypes()    獲得方法的傳入參數類型

getDeclaredMethod("方法名",參數類型.class,……)    獲得特定的方法

getDeclaredConstructors()    獲取所有的構造方法

getDeclaredConstructor(參數類型.class,……)    獲取特定的構造方法

getSuperclass()    獲取某類的父類

getInterfaces()    獲取某類實現的介面

 

三、反射的作用和動態代理 

  反射作用總結就是:1.動態地創建類的實例,將類綁定到現有的對象中,或從現有的對象中獲取類型。2.應用程式需要在運行時從某個特定的程式集中載入一個特定的類。

那麼什麼是動態代理呢?先給出百度的答案:動態代理,就是根據對象在記憶體中載入的Class類創建運行時類對象,從而調用代理類方法和屬性。

  代理模式的定義:為其他對象提供一種代理以控制對這個對象的訪問。在某些情況下,一個對象不適合或者不能直接引用另一個對象,而代理對象可以在客戶端和目標對象之間起到中介的作用。而代理模式又分為靜態代理和動態代理,先說靜態代理。

  靜態代理通俗點將就是自己手寫一個代理類,而動態代理則不用我們手寫,而是依賴於java反射機制,下麵以一個demo舉例。

  demo結構如圖:

  

  Subject是一個普通介面,裡面有個抽象的doSomething()的方法,而SubjectImpl.java是它的普通的實現類,如下所示。

    

  

  而HandProxy.java就是SubjectImpl的靜態代理類,代替了SubjectImpl完成doSomething的工作,如下所示

  

  這樣做的好處是對於doSomething方法來說,我用靜態代理類來實現,可以任意的在其中插入我需要額外做的事情,比如說記錄日誌。

  那麼AutoProxy.java就是動態代理類了,具體如下所示。

  

  這裡面首先想要做到動態代理,必須先實現這個InvocationHandler介面,然後我們主要看bind方法,參數tar是一個Object類型的對象,也就是需要被代理的對象SubjectImpl,

方法裡面有一個Proxy類,這個Proxy類提供了很多方法,這裡我們用的是newProxyInstance方法,它有三個參數,第一個是被代理類的類構造器,第二個指的是被代理類的介面,也就是Subject介面,第三個是實現這個代理的類,這裡就是本類。具體的來說,這個方法執行了下麵三步:

1.生成一個實現了參數interfaces里所有介面且繼承了Proxy的代理類的位元組碼,然後用參數里的classLoader載入這個代理類。

2.使用代理類父類的構造函數 Proxy(InvocationHandler h)來創造一個代理類的實例,將我們自定義的InvocationHandler的子類傳入。

3.返回這個代理類實例,因為我們構造的代理類實現了interfaces(也就是我們程式中傳入的subject.getClass().getInterfaces())里的所有介面,因此返回的代理類可以強轉成Subject類型來調用介面中定義的方法。

  而在調用每個代理類每個方法的時候,都用反射去調h的invoke方法(也就是我們自定義的InvocationHandler的子類中重寫的invoke方法),用參數傳遞了代理類實例、介面方法、調用參數列表,這樣我們在重寫的invoke方法中就可以實現對所有方法的統一包裝了。

  總結一下,靜態代理的優點是清晰易懂,但是如果說業務代碼很多,那麼在代理類裡面必須全部重新調用一遍,很麻煩。而動態代理,利用java反射機制,動態的生成了一個代理類,直接調用代理方法即可。

四、總結

  反射這一塊是博主最近在看框架源碼的時候總是遇到這類問題所以刻意去整理了一下,裡面有些東西其實我也研究的不是很深刻,動態代理這邊的源碼還有待深入挖掘,若有大神發現寫的不對的地方,還請多多指教,謝謝。

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 結論:設置溢出文字,不要直接在li標簽上設置,因為會有list-style-type的問題,還是包裹在span中,設置span省略號。 ...
  • 老師要求用web製作一個拼圖游戲。 發現的問題:點擊隨機生成拼圖的按鈕後,打亂的圖片會出現無法還原的情況。 發現過程:每次生成一個拼圖後會測試它怎麼拼回去,結果發現有時候拼不回去。 數學原理:如果兩個矩陣的逆序數的奇偶性相同,則其中一個矩陣通過若幹次變換以後必定能夠得到另一個矩陣。 問題原因:隨機生 ...
  • 記錄生活,每天一點點 原因: 博主工作上一需求,是檢查表單是否被修改。如果確定被修改了 才做某些操作。項目呢是一個有些年曆史的老項目了,基本上JQ在操作DOM,考慮到如果更換react或者angularjs 想想還是算了吧 換了事情更多了。就自己寫了一勉強能滿足當前業務需要的一小段JS。沒有什麼技術 ...
  • 1.JSON 與 JS 對象的關係 JSON 是 JS 對象的字元串表示法,它使用文本表示一個 JS 對象的信息,本質是一個字元串。 如var obj = {a: 'Hello', b: 'World'}; //這是一個對象,註意鍵名也是可以使用引號包裹的 var json = '{"a": "He ...
  • 本篇文章將介頁面佈局中的自適應佈局,常見的自適應佈局有以下2種:左列固定右列自適應、左右兩列固定中間自適應。 ...
  • 本教程案例github:https://github.com/axel10/dva_demo-Counter-and-list/tree/master 這次主要通過線上獲取用戶數據並且渲染成列表這個案例來演示dva.js。 整個開發流程概括下來應該是: 編寫用戶列表model(數據模型)-> 編寫修 ...
  • 通過JS實現對一系列checkbox的全選功能,實現全選/全不選、複位,反選等。 ...
  • 先講個黑色笑話: 半年前,一個誰也沒見過的日本浪人推出的理財產品突然在七俠鎮火爆起來,據說買上點屯著,不出幾月就能把同福客棧,甚至龍門鏢局都盤下。我們家小六的七舅老爺,賣掉祖宅也嚷嚷著要 all in。我覺得這事吧很是蹊蹺,好歹也是自家人嘛,不能讓老人家上當受騙 —— 所以 … 放著我來。我用我無雙 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...