Java 反射機制

来源:https://www.cnblogs.com/jmcui/archive/2018/09/18/9650710.html
-Advertisement-
Play Games

一、概念 Java 反射(Reflection)就是 Java 程式在運行時可以載入一個才知道類名的類,獲得類的完整構造方法,並實例化出對象,給對象屬性設定值或者調用對象的方法。這種在運行時動態獲取類的信息以及動態調用對象的方法的功能稱為 Java 的反射機制。 二、Class 類 Class 類繼 ...


一、概念

    Java 反射(Reflection)就是 Java 程式在運行時可以載入一個才知道類名的類,獲得類的完整構造方法,並實例化出對象,給對象屬性設定值或者調用對象的方法。這種在運行時動態獲取類的信息以及動態調用對象的方法的功能稱為 Java 的反射機制。

二、Class 類

    Class 類繼承自 Object 類,是 Java 反射機制的入口,封裝了一個類或介面的運行時信息,通過調用 Class 類的方法可以獲取到這些信息。怎麼理解這個 Class 類呢?如果說普通類是所有對象方法、屬性的集合,那就可以把這個 Class 類理解成是所有普通類的集合。

    下麵列舉了獲取 Class 類的幾種方法:

public class TestClass {
    
    public static void main(String[] args) throws ClassNotFoundException {
        // 1、 Class.forName();
        Class<?> aClass0 = Class.forName("java.lang.Object");
        // 2、類名.Class
        Class<Integer> aClass1 = Integer.class;
        // 3、包裝類.TYPE —— 返回基本類型的 Class 引用,基本類型在虛擬機運行時就已經載入了它的Class
        Class<Integer> aClass2 = Integer.TYPE;
        // 4、對象名.getClass()
        String str = "Hello, World";
        Class<? extends String> aClass3 = str.getClass();
        // 5、Class類.getSuperClass() —— 獲得父類的 Class 對象
        Class<?> aClass4 = aClass3.getSuperclass();

        System.out.println(aClass0.getName());
        System.out.println(aClass1.getName());
        System.out.println(aClass2.getName());
        System.out.println(aClass3.getName());
        System.out.println(aClass4.getName());
    }
}

三、獲取類信息

    為了測試 Java 的反射機制,我新建了一對父子類,其中涵蓋了四種封裝屬性,以儘可能的測試多種類信息的獲取:

vpublic class Vehicle {

    private String color;
    protected Integer seat;
    int year;
    public Date createdOn;

    private String getColor() {
        return color;
    }

    protected Integer getSeat() {
        return seat;
    }

    int getYear() {
        return year;
    }

    public Date getCreatedOn() {
        return createdOn;
    }
}
Vehicle.java
public class Car extends Vehicle {

    private String brand;
    protected Integer a;
    int b;
    public Date updatedOn;

    public Car(){}

    private Car(String brand, Integer a, int b, Date updatedOn) {
        this.brand = brand;
        this.a = a;
        this.b = b;
        this.updatedOn = updatedOn;
    }

    private String getBrand() {
        return brand;
    }

    protected Integer getA() {
        return a;
    }

    int getB() {
        return b;
    }

    public Date getUpdatedOn() {
        return updatedOn;
    }
}
Car.java

    1、獲取方法

    Class 類對方法的獲取主要通過以下兩種方式:

Method[] getMethods() 返回該類或介面的所有可訪問公共方法(含繼承的公共方法)。

Method[] getDeclaredMethods() 返回該類或介面的所有方法(不含繼承的方法)。

public class TestMethod {

    public static void main(String[] args) {
        Class<Car> carClass = Car.class;
        Method[] methods = carClass.getMethods();
        Method[] declaredMethods = carClass.getDeclaredMethods();

        for (Method method : methods) {
        //for (Method method : declaredMethods) {
            System.out.println("方法名:" + method.getName());
            System.out.println("該方法所在的類或介面:" + method.getDeclaringClass());
            System.out.println("該方法的參數列表:" + method.getParameterTypes());
            System.out.println("該方法的異常列表:" + method.getExceptionTypes());
            System.out.println("該方法的返回值類型:" + method.getReturnType());
        }
    }
}

    2、獲取屬性

    Class 類對屬性的獲取主要通過以下兩種方式:

Field[] getFields() :存放該類或介面的所有可訪問公共屬性(含繼承的公共屬性)。

Field[] getDeclaredFields():存放該類或介面的所有屬性(不含繼承的屬性)。

public class TestField {

    public static void main(String[] args) {
        Class<Car> carClass = Car.class;
        Field[] fields = carClass.getFields();
        Field[] declaredFields = carClass.getDeclaredFields();
        //for (Field field : fields) {
        for (Field field : declaredFields) {
            System.out.println("屬性名稱是:" + field.getName());
            System.out.println("該屬性所在的類或介面是:" + field.getDeclaringClass());
            System.out.println("該屬性的類型是:" + field.getType());
            // field.getModifiers() 以整數形式返回由此 Field 對象表示的屬性的 Java 訪問許可權修飾符
            System.out.println("該屬性的修飾符是:" + Modifier.toString(field.getModifiers()));
        }
    }
}

    3、獲取構造函數

     Class 類對構造方法的獲取主要通過以下兩種方式:

Constructor<?>[] getConstructors() :返回該類或介面的所有的公共構造方法

Constructor<?>[] getDeclaredConstructors():返回該類或介面的所有構造方法

public class TestConstructor {

    public static void main(String[] args) throws NoSuchMethodException {
        Class<Car> carClass = Car.class;
        Constructor<?>[] constructors = carClass.getConstructors();
        Constructor<?>[] declaredConstructors = carClass.getDeclaredConstructors();
        Constructor<Car> carConstructor = carClass.getDeclaredConstructor(String.class, Integer.class, Integer.TYPE, Date.class);

        //for (Constructor constructor : declaredConstructors) {
        for (Constructor constructor : constructors) {
            System.out.println("該構造器的名稱是:" + constructor.getName());
            System.out.println("該構造器所在的類或介面是:" + constructor.getDeclaringClass());
            //返回構造方法的參數類型
            constructor.getParameterTypes();
        }
    }
}

四、動態調用

    到目前為止,我們都是通過 Class 類的方法獲取對應類屬性、方法和構造函數的詳細信息。接下來我們將通過這些信息,來動態創建對象、修改屬性和動態調用方法。

public class Test {

    public static void main(String[] args) throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
        Class<Car> carClass = Car.class;
        // 1、實例化對象
        // 調用 Class 類的newInstance();要求對應類必須有無參構造函數,相當於 Car car = new Car()
        Car car = carClass.newInstance();
        // 調用構造器的newInstance(Object ... initargs);
        Constructor<Car> declaredConstructor = carClass.getDeclaredConstructor(String.class, Integer.class, Integer.TYPE, Date.class);
        // 取消訪問許可權控制,即使是 private 許可權也可以訪問
        declaredConstructor.setAccessible(true);
        Car car1 = declaredConstructor.newInstance("brand", 21, 21, new Date());
        System.out.println(car1.getUpdatedOn());

        // 2、修改屬性
        Field brand = carClass.getDeclaredField("brand");
        brand.setAccessible(true);
        System.out.println("取消訪問許可權控制後的值:" + brand.get(car1));
        brand.set(car1, "dnarb");
        System.out.println("修改屬性後的值是:" + brand.get(car1));

        // 3、調用方法
        Method getBrand = carClass.getDeclaredMethod("getBrand");
        getBrand.setAccessible(true);
        System.out.println("調用反射方法得到的值是:" + getBrand.invoke(car1));
    }
}

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

-Advertisement-
Play Games
更多相關文章
  • [TOC] 翻譯自《Demo Week: Time Series Machine Learning with h2o and timetk》 原文鏈接:https://www.business science.io/code tools/2017/10/28/demo_week_h2o.html 文 ...
  • 【前提】 LAMP環境搭建完成且基本配置完成 本次LAMP環境使用的是源碼包安裝,如何搭建LAMP環境會在後面總結。 遠程工具為:SCRT 環境:VMware下的linux虛擬機 本文只是簡單的總結,先寫出來給一些朋友觀看,後面會有從LAMP環境搭建到php網站部署的完整文章,所以這篇排版和內容會過 ...
  • 1.十進位與二進位之間的轉換 (1)十進位轉二進位的方法:使用十進位的數據不斷除以2,直到商為0為止,從下往上取餘就是對應的二進位。 (2)二進位轉十進位:使用二進位的每一位乘以2的n次方,n從0開始,每次遞增1,然後把各部分的數據相加即可。 2.十進位,八進位,二進位之間的轉換 (1)十進位轉八進 ...
  • 需求: 用網頁打開 登陸框:brokerId,investorId,密碼,登陸 下單框:選擇方向:買、賣,選擇開平:開,平,平今,價格,數量。 持倉框:合約名稱,多空,手數,可平,持倉均價,持倉盈虧 掛單框:合約名稱,開平,委托價,委托量,掛單量? 委托框:合約名稱,狀態,開平,委托價,委托量,已成 ...
  • 輸入一個正整數數組,把數組裡所有數字拼接起來排成一個數,列印能拼接出的所有數字中最小的一個。例如輸入數組{3,32,321},則列印出這三個數字能排成的最小數字為321323。 解法1 1.數組排序,使用自定義排序規則是 a.b>b.a a 和 b互換位置 2.usort函數的使用 function... ...
  • 題意 題目鏈接 Sol 傳說中的吉司機線段樹??感覺和BZOJ冒險那題差不多,就是強行剪枝。。。 這題最坑的地方在於對於操作1,$C >= 0$, 操作2中需要對0取max,$a[i] >= 0$,這不就是統計最小值出現的次數麽?? 按照套路 維護好區間賦值標記 / 區間加法標記 / 區間max標記 ...
  • 很重要的 搞清楚happen-before -->Java併發編程之happens-before 感謝 Java併發編程:volatile關鍵字解析 可見性:一個線程對主記憶體的修改可以及時的被其他線程觀察到。 有序性:一個線程觀察其他線程中的指令執行順序,由於指令 重排序的存在,該觀察結果一般雜亂無 ...
  • 恢復內容開始 Serializer 序列化器是DRF框架中重要的組成部分,可以快速根據 Django ORM 或者其它庫自動序列化/反序列化; Serializer 作用: 1. 進行數據的校驗 2. 對數據對象進行轉換 代碼中使用的模型類: 1. 書籍模型類: 2. 書中的英雄模型類: 說明: 書 ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...