反射,動態代理隨筆

来源:http://www.cnblogs.com/xxhz/archive/2017/06/25/7078546.html
-Advertisement-
Play Games

反射的基本概述 一個class文件被載入到記憶體的時候,JVM就會經行解剖,把這個class文件的所有成員全部解剖出來,然後JVM會創建一個Class對象,把這些成員信息全部都封裝起來,所謂反射就是指:我們獲取到這個Class對象,就相當於獲取到了該類的所有成員信息,我們就能操又該類的所有成員. Ja ...


  • 反射的基本概述
    • 一個class文件被載入到記憶體的時候,JVM就會經行解剖,把這個class文件的所有成員全部解剖出來,然後JVM會創建一個Class對象,把這些成員信息全部都封裝起來,所謂反射就是指:我們獲取到這個Class對象,就相當於獲取到了該類的所有成員信息,我們就能操又該類的所有成員.
    • Java反射機制是在運行狀態中,對於任意一個類,都能夠知道這類的所有屬性和方法;
    • 對於任意一個對象,都能夠調用它的任意一個方法和屬性;
    • 這種動態獲取的細心以及動態調用它的任意一個方法和屬性;
    • 這種動態獲取的信息以及動態調用對象的方法的功能稱為java語言的反射機制.
    • 要想解剖一個類,必須要獲取到該類的位元組碼文件對象.
  • 獲取Class對象的三種方式
    • 通過Class.forName()方法獲取:

         

static Class<?>

   

  

forName(String className)

          返回與帶有給定字元串名的類或介面相關聯的 Class 對象。

className--完整類名,eg:com.test.Test01

  • 通過類名直接獲取Class對象:

    eg: Class clazz=Person.class;

  • 通過對象獲取Class對象

    eg:Class clazz=new Person().getClass();

  • 寫程式的階段
    • 三種方式

Object類的getClass(類的完整類名)方法

讀取配置文件,判斷兩個對象是否是同一個位元組碼文件

靜態屬性class(鎖對象)

當作靜態方法的鎖對象

Class類中靜態方法forName()

讀取配置文件, 判斷是否是同一個位元組碼對象

   

  • 代碼案例
  • 1  package com.heima.reflect;                
    
    2                  import com.heima.bean.Person;
    
    3                 
    
    4                  public class Demo1_Reflect {
    
    5                 
    
    6                          /**
    
    7                           * @param args
    
    8                           * @throws ClassNotFoundException
    
    9                           */
    
    10                          public static void main(String[] args) throws ClassNotFoundException {
    
    11                                  Class clazz1 = Class.forName("");
    
    12                                  // 介面 a = 實現類的對象 a.方法
    
    13                                  //方式一
    
    14                                  Class clazz2 = Person.class;
    
    15                                  //方式二
    
    16                                  Person p = new Person();
    
    17                                  Class clazz3 = p.getClass();
    
    18                                  //方式三
    
    19                                  System.out.println(clazz1 == clazz2);
    
    20                                  System.out.println(clazz2 == clazz3);
    
    21                          }
    
    22                 
    
    23                  }
  • Class.forName()讀取配置文件_代碼示例
  • 1 package com.heima.reflect;
    
    2
    
    3 import java.io.BufferedReader;
    
    4 import java.io.FileReader;
    
    5
    
    6 public class Demo2_Reflect {
    
    7
    
    8         /**
    
    9          * * 榨汁機(Juicer)榨汁的案例
    
    10          * 分別有水果(Fruit)蘋果(Apple)香蕉(Banana)桔子(Orange)榨汁(squeeze)
    
    11          * @throws IOException
    
    12          */
    
    13         public static void main(String[] args) throws Exception {
    
    14                 Juicer j = new Juicer();                                                                        //創建榨汁機
    
    15                 //j.run(new Apple());
    
    16                 //j.run(new Orange());
    
    17                 BufferedReader br = new BufferedReader(new FileReader("config.properties"));//com.heima.reflect.Apple
    
    18                 Class clazz = Class.forName(br.readLine());                                        //獲取該類的位元組碼文件
    
    19                 Fruit f = (Fruit) clazz.newInstance();                                                //創建實例對象
    
    20                 
    
    21                 j.run(f);
    
    22         }
    
    23 }
    
    24 interface Fruit {
    
    25         public void squeeze();
    
    26 }
    
    27 class Apple implements Fruit {
    
    28         public void squeeze() {
    
    29                 System.out.println("榨出一杯蘋果汁兒");
    
    30         }
    
    31 }
    
    32
    
    33 class Orange implements Fruit {
    
    34         public void squeeze() {
    
    35                 System.out.println("榨出一杯橘子汁兒");
    
    36         }
    
    37 }
    
    38
    
    39 class Juicer {
    
    40         /*public void run(Apple a) {
    
    41                 a.squeeze();
    
    42         }
    
    43         
    
    44         public void run(Orange o) {
    
    45                 o.squeeze();
    
    46         }*/
    
    47         
    
    48         public void run(Fruit f) {
    
    49                 f.squeeze();
    
    50         }
    
    51
    
    52 }
  • 通過反射獲取構造函數_Constructor
    • 成員方法

         

 T

newInstance()

          創建此 Class 對象所表示的類的一個新實例。

 Constructor<T>

getConstructor(Class<?>... parameterTypes)

          返回一個 Constructor 對象,它反映此 Class 對象所表示的類的指定公共構造方法。

 Constructor<?>[]

getConstructors()

          返回一個包含某些 Constructor 對象的數組,這些對象反映此 Class 對象所表示的類的所有公共構造方法。

 Constructor<T>

getDeclaredConstructor(Class<?>... parameterTypes)

          返回一個 Constructor 對象,該對象反映此 Class 對象所表示的類或介面的指定構造方法。

 Constructor<?>[]

getDeclaredConstructors()

          返回 Constructor 對象的一個數組,這些對象反映此 Class 對象表示的類聲明的所有構造方法

   

  • 創建對象_代碼示例

       

       

  • 通過反射獲取成員變數_Field
    • 成員方法
      • Class類

 Field

getField(String name)

          返回一個 Field 對象,它反映此 Class 對象所表示的類或介面的指定公共成員欄位。

 Field[]

getFields()

          返回一個包含某些 Field 對象的數組,這些對象反映此 Class 對象所表示的類或介面的所有可訪問公共欄位。

 Field

getDeclaredField(String name)

          返回一個 Field 對象,該對象反映此 Class 對象所表示的類或介面的指定已聲明欄位。

 Field[]

getDeclaredFields()

          返回 Field 對象的一個數組,這些對象反映此 Class 對象所表示的類或介面所聲明的所有欄位。

   

  • Field類

       

void

setAccessible(boolean flag)

          將此對象的 accessible 標誌設置為指示的布爾值。

 void

set(Object obj, Object value)

          將指定對象變數上此 Field 對象表示的欄位設置為指定的新值。

   

   

  • 調用方法_代碼示例

       

       

  • 通過反射獲取成員方法_Method
    • Class類

         

 Method

getMethod(String name, Class<?>... parameterTypes)

          返回一個 Method 對象,它反映此 Class 對象所表示的類或介面的指定公共成員方法。

 Method[]

getMethods()

          返回一個包含某些 Method 對象的數組,這些對象反映此 Class 對象所表示的類或介面(包括那些由該類或介面聲明的以及從超類和超介面繼承的那些的類或介面)的公共 member 方法。

 Method

getDeclaredMethod(String name, Class<?>... parameterTypes)

          返回一個 Method 對象,該對象反映此 Class 對象所表示的類或介面的指定已聲明方法。

 Method[]

getDeclaredMethods()

          返回 Method 對象的一個數組,這些對象反映此 Class 對象表示的類或介面聲明的所有方法,包括公共、保護、預設(包)訪問和私有方法,但不包括繼承的方法。

   

  • Method類

       

 Object

invoke(Object obj, Object... args)

          對帶有指定參數的指定對象調用由此 Method 對象表示的底層方法。

  • 案例

       

       

  • 通過反射越過泛型檢查
    • 需求:ArrayList的一個對象,在這個集合中添加一個字元串數據,如何實現呢?
    • 泛型只在編譯期有效,在運行期會被擦除掉
    • 代碼示例
    • 1 package com.heima.test;
      
      2
      
      3 import java.lang.reflect.Method;
      
      4 import java.util.ArrayList;
      
      5
      
      6 public class Test1 {
      
      7
      
      8         /**
      
      9          * @param args
      
      10          * ArrayList<Integer>的一個對象,在這個集合中添加一個字元串數據,如何實現呢?
      
      11          * 泛型只在編譯期有效,在運行期會被擦除掉
      
      12          * @throws Exception
      
      13          */
      
      14         public static void main(String[] args) throws Exception {
      
      15                 ArrayList<Integer> list = new ArrayList<>();
      
      16                 list.add(111);
      
      17                 list.add(222);
      
      18                 
      
      19                 Class clazz = Class.forName("java.util.ArrayList");                                //獲取位元組碼對象
      
      20                 Method m = clazz.getMethod("add", Object.class);                                //獲取add方法
      
      21                 m.invoke(list, "abc");
      
      22                 
      
      23                 System.out.println(list);
      
      24                 
      
      25         }
      
      26
      
      27 }
  • 動態代理的概述和實現
    • 動態代理:在程式運行過程中產生的這個對象,而程式運行過程中產生對象其實就是我們剛纔反射講解的內容,所以,動態代理其實就是通過反射來生成一個代理
    • 在Java中java.lang.reflect包下提供了一個Proxy類和一個InvocationHandler介面,通過使用這個類和介面就可以生成動態代理對象。JDK提供的代理只能針對介面做代理。我們有更強大的代理cglib,Proxy類中的方法創建動態代理類對象.
    • 成員方法
      • proxy類

           

static Object

newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)

          返回一個指定介面的代理類實例,該介面可以將方法調用指派到指定的調用處理程式。

  • 實現InvocationHandler介面重寫invoke方法

 Object

invoke(Object proxy, Method method, Object[] args)

          在代理實例上處理方法調用並返回結果。

   

  • 代碼案例
    • MyInvocationHandler.java_代碼示例
    • 1 package com.heima.動態代理;
      
      2
      
      3 import java.lang.reflect.InvocationHandler;
      
      4 import java.lang.reflect.Method;
      
      5
      
      6 public class MyInvocationHandler implements InvocationHandler {
      
      7         private Object target;
      
      8         
      
      9         public MyInvocationHandler(Object target) {
      
      10                 this.target = target;
      
      11         }
      
      12         @Override
      
      13         public Object invoke(Object proxy, Method method, Object[] args)
      
      14                         throws Throwable {
      
      15                 System.out.println("許可權校驗");
      
      16                 method.invoke(target, args);                                        //執行被代理target對象的方法
      
      17                 System.out.println("日誌記錄");
      
      18                 return null;
      
      19         }
      
      20
      
      21 }
    • Student.java_代碼示例
    • 1 package com.heima.動態代理;
      
      2
      
      3 public interface Student {
      
      4         public void login();
      
      5         
      
      6         public void submit();
      
      7 }
    • StudentImp.java_代碼示例
    • 1 package com.heima.動態代理;
      
      2
      
      3 public class StudentImp implements Student {
      
      4
      
      5         @Override
      
      6         public void login() {
      
      7                 System.out.println("登錄");
      
      8         }
      
      9
      
      10         @Override
      
      11         public void submit() {
      
      12                 System.out.println("提交");
      
      13         }
      
      14
      
      15 }
      
         
      
      User.java_代碼示例
      1 package com.heima.動態代理;
      
      2
      
      3 public interface User {
      
      4         public void add();
      
      5         
      
      6         public void delete();
      
      7 }
      
         
      
      UserImp.java_代碼示例
      1 package com.heima.動態代理;
      
      2
      
      3 public class UserImp implements User {
      
      4
      
      5         @Override
      
      6         public void add() {
      
      7                 //System.out.println("許可權校驗");
      
      8                 System.out.println("添加功能");
      
      9                 //System.out.println("日誌記錄");
      
      10         }
      
      11
      
      12         @Override
      
      13         public void delete() {
      
      14                 //System.out.println("許可權校驗");
      
      15                 System.out.println("刪除功能");
      
      16                 //System.out.println("日誌記錄");
      
      17         }
      
      18
      
      19 }
        
    • Test.java_代碼示例
      1 package com.heima.動態代理;
      
      2
      
      3 import java.lang.reflect.Proxy;
      
      4
      
      5 public class Test {
      
      6
      
      7         /**
      
      8          * @param args
      
      9          */
      
      10         public static void main(String[] args) {
      
      11                 /*UserImp ui = new UserImp();
      
      12                 ui.add();
      
      13                 ui.delete();
      
      14                 
      
      15                 System.out.println("-------------------------------");*/
      
      16                 /*
      
      17                  * public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,
      
      18                  * InvocationHandler h)
      
      19                  */
      
      20                 /*MyInvocationHandler m = new MyInvocationHandler(ui);
      
      21                 User u = (User)Proxy.newProxyInstance(ui.getClass().getClassLoader(), ui.getClass().getInterfaces(), m);
      
      22                 u.add();
      
      23                 u.delete();*/
      
      24                 
      
      25                 StudentImp si = new StudentImp();
      
      26                 si.login();
      
      27                 si.submit();                
      
      28                 System.out.println("-------------------------------");
      
      29                 MyInvocationHandler m = new MyInvocationHandler(si);
      
      30                 Student s = (Student)Proxy.newProxyInstance(si.getClass().getClassLoader(), si.getClass().getInterfaces(), m);
      
      31                 
      
      32                 s.login();
      
      33                 s.submit();
      
      34         }
      
      35
      
      36 }

       


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

-Advertisement-
Play Games
更多相關文章
  • 一款用JAVA語言開發的Redis管理及監控工具treeNMS橫空出世了。 ...
  • 今天啟動虛擬機,遇到如下錯誤: RAMDISK: incomplete write (31522 != 32768) write error Kernel panic not syncing : VFS: Unable to mount root fs on unknown block(0,0) 網 ...
  • VIM詳細命令有很多,我們選用一些常用的入門命令,足以對付日常的代碼編輯工作了,如果日後有需要使用其他命令,再來查詢也不遲。 vim一般有3種編輯模式,分別是插入模式,正常模式(normal mode),末行模式。 以下主要是在正常模式下的操作,其他模式操作會註明相關模式 1.1 移動游標 h >每 ...
  • 最近手頭上的項目終於忙得差不多了,想起好久沒有更新了的NanUI,再看著每天QQ群未讀消息閃爍的標誌,突然才發現似乎愧對了群里各位喜愛NanUI的朋友們。於是乎,就想趁這幾天有時間,好好的修複一下NanUI已知的BUG,再用有限的時間推進整個項目的進度。 在複習代碼的時候,想起了群里有朋友提出說Na ...
  • 空(None) None可以用來表示某一個變數的值缺失,類似於其他語言中的null。 像其他的空值:0,[]和空的string,布爾變數給的是False而不是True。 結果是: 當一個函數沒有返回任何值時,就會返回None: 結果是: Hi None 字典(Dictionaries) 字典是一種給 ...
  • 在上一節中講解了歸併排序的遞歸版《4.比較排序之歸併排序(遞歸)》,通常來講,遞歸版的歸併排序要更為常用,本節簡單介紹下非遞歸版的歸併排序。思路和遞歸版相同,均為先分解後合併,非遞歸的重點在於如何確定併合理的分解待排序數組。 對於遞歸我們是這麼做的: 對於非遞歸來講,切分的不向遞歸從大到小,非遞歸實 ...
  • 在編寫穩定可靠的軟體服務時經常用到輸出堆棧信息,以便用戶/開發者獲取準確的運行信息。常用在日誌輸出,錯誤報告,異常檢測。本文介紹Linux與Windows下用C++獲取堆棧信息的方法。 ...
  • JSON-lib包(最關鍵的兩個類分別是JSONObject和JSONArray)完成對json的構造和一些基本方法的使用。 二者區別: ①JSONObject構造的字元串是鍵值對形式(key:value),多個鍵值對間以英文逗號連接; ②JSONArray構造的字元串是數組形式([array1,a ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...