反射技術初步

来源:https://www.cnblogs.com/LittleTreasureBox/archive/2018/04/16/8859115.html
-Advertisement-
Play Games

類的載入概述 載入 就是指將class文件讀入記憶體,併為之創建一個Class對象。任何類被使用時系統都會建立一個Class對象。 連接 驗證 是否有正確的內部結構,並和其他類協調一致 準備 負責為類的靜態成員分配記憶體,並設置預設初始化值 解析 將類的二進位數據中的符號引用替換為直接引用 初始化 略 ...


類的載入概述

當程式要使用某個類時,如果該類還未被載入到記憶體中,則系統會通過載入,連接,初始化三步來實現對這個類進行初始化。

載入

  • 就是指將class文件讀入記憶體,併為之創建一個Class對象。任何類被使用時系統都會建立一個Class對象。

連接

  • 驗證 是否有正確的內部結構,並和其他類協調一致
  • 準備 負責為類的靜態成員分配記憶體,並設置預設初始化值
  • 解析 將類的二進位數據中的符號引用替換為直接引用

初始化

類的載入時機

  • 創建類的實例
  • 訪問類的靜態變數,或者為靜態變數賦值
  • 調用類的靜態方法
  • 使用反射方式來強制創建某個類或介面對應的java.lang.Class對象
  • 初始化某個類的子類
  • 直接使用java.exe命令來運行某個主類

類載入器的概述

負責將.class文件載入到記憶體中,併為之生成對應的Class對象。

類載入器的分類

  • Bootstrap ClassLoader 根類載入器
  • Extension ClassLoader 擴展類載入器
  • Sysetm ClassLoader 系統類載入器

類載入器的作用

Bootstrap ClassLoader 根類載入器

  • 也被稱為引導類載入器,負責Java核心類的載入
  • 比如,System,String 等。在JDK中JRE的lib目錄下rt.jar文件中

Extension ClassLoader 擴展類載入器

  • 負責JRE的擴展目錄中jar包的載入。
  • 在JDK中JRE的lib目錄下的ext目錄

Sysetm ClassLoader 系統類載入器

  • 負責在JVM啟動時載入來自java命令的class文件,以及classpath環境變數所指定的jar包和類路徑

反射技術

就是動態載入一個指定的類,並獲取該類中的所有的內容。將位元組碼文件和位元組碼文件中的內容都封裝成對象,這樣以來,就可以方便地進行如下操作:
1. 在運行時判斷一個對象所屬的類;
2. 在運行時構造類的對象;
3. 在運行時訪問java對象的屬性,方法,構造方法等。

Class類

Java程式在運行期間,Java運行時系統始終會為所有對象維護一個被稱為運行時的類型標識(runtime type ID)。每個標識跟蹤著每個對象所屬的類,保存這些標識的類就是Class類。

  1. 如果拿到了對象,不知道是什麼類型,用於獲得對象的類型。
    Object obj = new Person();
    Class clazz1 = obj.getClass();
  2. 根據指定的類名來獲得,用於類載入。如果字元串不是類名或介面名就會拋出checkedexception,無論何時使用這個方法,都應該提供一個異常處理器。
    String classname = "com.mysql.jdbc.Driver";
    Class clazz = Class.forName(classname);
  3. 明確地獲得某個類的Class對象,主要用於傳參。
    Class clazz = Person.class;
    Class clazz = int.class;
  • 註意,一個Class對象實際上描述了一個類型,而這個類型未必一定是一種類。例如int不是類,但int.class一個class類型的對象。

Class.forName()讀取配置文件舉例

創建輸入流對象,關聯配置文件
BufferedReader br = new BufferedReader(new FileReader("config.properties"));
讀取配置文件一行內容,獲取該類的位元組碼對象
Class<?> clazz = Class.forName(br.readLine());
通過位元組碼對象創建實例對象.方法調用預設的構造器(無參的),如果沒有無參構造器就會跑出一個異常。
Fruit f = (Fruit) clazz.newInstance();
使用
Juicer j = new Juicer();
j.run(f);

通過反射獲取帶參構造方法

Constructor
Class類的newInstance()方法是使用該類無參的構造函數創建對象, 如果一個類沒有無參的構造函數, 就不能這樣創建了,可以調用Class類的getConstructor(String.class,int.class)方法獲取一個指定的構造函數然後再調用Constructor類的newInstance("張三",17)方法創建對象。

通過反射獲取成員變數

Field
Class.getField(String)方法可以獲取類中的指定域(非私有的), 通過set(obj, "李四")方法可以設置指定對象上該域的值。如果是私有的可以用getDeclaedField("name")方法獲取域, 然後調用setAccessible(true)設置訪問許可權,再調用get(obj)可以獲取指定對象中該域的值。

通過反射獲取方法

Method
Class.getMethod(String name, Class<?>... parameterTypes) 和Class.getDeclaredMethod(String name, Class<?>... parameterTypes)方法可以獲取類中的指定方法。
調用invoke(Object, Object...)可以調用該方法, 如,Class.getMethod("run",int.class).invoke(obj,10)

通過反射越過泛型檢查

泛型只在編譯期有效,在運行期會被擦除掉。

ArrayList<Integer>的一個對象list中,添加一個字元串數據。

ArrayList<Integer> list = new ArrayList<>();
list.add(100);
list.add(200);
Class clazz = Class.forName("java.util.ArrayList"); //獲取位元組碼對象
Method m = clazz.getMethod("add", Object.class); //獲得add(E e)方法
m.invoke(list, "abc"); // invoke(obj, Obj...args)
System.out.println(list);

動態代理

在Java中`java.lang.reflect`包下提供了一個`Proxy`類和一個`InvocationHandler`介面,通過使用這個類和介面就可以生成動態代理對象。JDK提供的代理只能針對介面做代理。

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

  • 利用代理可以在運行時創建一個實現了一組特定介面的新類。
  • 這種功能只有在編譯時無法確定要實現哪些介面時才有必要使用。

  • 代理類能夠實現指定的介面。尤其是,它具有下列方法:
  1. 指定介面的全部方法。
  2. Object類中的全部方法。
不能在運行時直接定義上述方法的新代碼。而是要提供一個調用處理器(invocationhandler)。調用處理器是實現了`InvocationHandler`介面的類對象。
  • InvocationHandler介面中有一個方法:
    Object invoke(Object proxy , Method method , Object[] args)
 `public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)`最終會調用`InvocationHandler`的方法`InvocationHandler Object invoke(Object proxy,Method method,Object[] args)`
  • 無論何時調用代理對象的方法,調用處理器的invoke方法都會被調用,並向其傳遞Method對象和原始的調用參數。
    調用處理器必須給出處理調用的方式

實現代理:

public class TestProxy {

    public static void main(String[] args) {
        StuendImp stu = new StuendImp();
        MyInvocationHandler myinvocationhandler =  new MyInvocationHandler(stu);
        Student s = (Student)Proxy.newProxyInstance(stu.getClass().getClassLoader(), stu.getClass().getInterfaces(), myinvocationhandler);
        stu.login();
        stu.submit();
        System.out.println("-------代理後--------");
        s.login();
        s.submit();
    }

}

stu為被代理對象。 s為代理對象。myinvocationhandler為調用處理器

介面:

public interface Student {
    public void login();
    public void submit();
}

實現類:

public class StuendImp implements Student {
    @Override
    public void login() {
        System.out.println("登錄操作");

    }
    @Override
    public void submit() {
        System.out.println("提交操作");
    }
}

調用處理器:

public class MyInvocationHandler implements InvocationHandler {
    private Object target;
    public MyInvocationHandler(Object object) {
        super();
        this.target = object;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("許可權校驗..");
        method.invoke(target, args);
        System.out.println("日誌記錄..");
        return null;
    }

}

(-̇᷇̂ᴥ ̇᷇̂-)(-̇᷇̂ᴥ ̇᷇̂-)(-̇᷇̂ᴥ ̇᷇̂-)有誤或不足之處,歡迎交流;喜歡就頂,別剋制。(୨୧•͈ᴗ•͈)◞ᵗʱᵃᵑᵏઽ


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

-Advertisement-
Play Games
更多相關文章
  • layout: post title: 2016 03 11 信息系統實踐手記2 客戶端啟動速度調優思路 key: 20160311 tags: 客戶端 調優 測試 伺服器 GIS WPF 模塊 壓力 瓶頸 modify_date: 2016 03 11 信息系統實踐手記2 客戶端啟動速度調優思路 ...
  • 手把手教你寫網路爬蟲(3) 作者:拓海 摘要:從零開始寫爬蟲,初學者的速成指南! 封面: 介紹 大家好!我們從今天開始學習開源爬蟲框架Scrapy,如果你看過《手把手》系列的前兩篇,那麼今天的內容就非常容易理解了。細心的讀者也許會有疑問,為什麼不學出身名門的Apache頂級項目Nutch,或者人氣飆 ...
  • 上一篇詳細的分析了獨占模式下如何對線程進行處理:簡單的總結是Java面向用戶提供了鎖的機制,後面的實現使用了一個同步隊列,由於隊列具有先進先出的特點,把每個線程都構造成為隊列中的節點,每個節點定義一個狀態值,符合狀態的節點(線程)才可以有執行的機會,執行完釋放,後面的線程只能是等待著前面的執行結果進 ...
  • 問題 之前一直用的 Laravel 5.4,資料庫也是直接寫 sql 的,感覺可定製性更強,順便鍛煉下 sql。這次改用了 Laravel 5.5,索性用遷移建庫試試,結果報錯如下: SQLSTATE[HY000]: General error: 1215 Cannot add foreign ke ...
  • `python 網路爬蟲` 概述 這是一個簡單的python爬蟲程式,僅用作技術學習與交流,主要是通過一個簡單的實際案例來對網路爬蟲有個基礎的認識。 什麼是網路爬蟲 簡單的講,網路爬蟲就是模擬人訪問web站點的行為來獲取有價值的數據。專業的解釋: "百度百科" 分析爬蟲需求 確定目標 爬取豆瓣熱度在 ...
  • 1. 涉及主要jdk api java.lang.reflect.InvocationHandler; public interface InvocationHandler { /** * Processes a method invocation on a proxy instance and r ...
  • https://blog.csdn.net/arredando/article/details/76684764 引用CSDN ...
  • 可以直接作用於for迴圈的數據類型有以下幾種: 一類是集合數據類型,如list、tuple、dict、set、str等; 一類是generator,包括生成器和帶yield的generator function。 可以直接作用於for迴圈的對象統稱為可迭代對象:Iterable。 可以使用isins ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...