【Java面試指北】反射(1) 初識反射

来源:https://www.cnblogs.com/shuofxz/archive/2022/12/18/16991309.html
-Advertisement-
Play Games

如果你被問到:什麼是反射?為什麼需要反射、以及反射的應用?你會如何回答呢? 本篇會帶大家初識反射,瞭解反射概念和基本應用。反射的原理以及深入源碼的探究將會在後面幾篇介紹。 ...


如果你被問到:什麼是反射?為什麼需要反射、以及反射的應用?你會如何回答呢?
本篇會帶大家初識反射,瞭解反射概念和基本應用。反射的原理以及深入源碼的探究將會在後面幾篇介紹。

一、什麼是反射?

要理解什麼是反射,我們先看看什麼是「正射」,一個常見的獲取Student的正射如下:

Student student = new Student();

通常 我們都是直接聲明,或者通過 new Student() 直接獲取一個 Student 類,然後再使用。而一個反射的例子如下:

// 這裡的“com.demo.Student”是需要反射的類的全限定名(包名+類名)
Class clz = Class.forName("com.demo.Student")	
Object stu = clz.newInstance();

先獲取實例的Class類,然後再通過其Class類生成一個Student的Instance。以上兩種方式(new Student和clz.newInstance)是效果是等價的,都是獲取到了一個Student 的實例。

那麼什麼是反射呢?反射是Java中的一個重要的特性,使用反射可以在運行時動態生成對象、獲取對象屬性以及調用對象方法。
Oracle 官方對反射的解釋是:

Reflection enables Java code to discover information about the fields, methods and constructors of loaded classes, and to use reflected fields, methods, and constructors to operate on their underlying counterparts, within security restrictions.
The API accommodates applications that need access to either the public members of a target object (based on its runtime class) or the members declared by a given class. It also allows programs to suppress default reflective access control.

反射的核心是 JVM 在運行時才動態載入類或調用方法/訪問屬性,它不需要事先(寫代碼的時候或編譯期)知道運行對象是誰。

反射的問題:
這裡先簡單提一下:反射相當於一系列解釋操作,通知 JVM 要做的事情,性能比直接的 Java 代碼要慢很多。

二、為什麼需要反射?

舉一個直觀的例子(僅為了說明其中一種用法):
如果我讓你寫一個根據運行時輸入的名字進行列印輸出,你會寫出類似下麵的代碼:

public void sayHello(String name) {
    // 在運行前根本不知道 name 是什麼,只有在運行時 name 才會被確認並列印出來
    System.out.println("hello, " + name);
}

那麼同樣的,在寫代碼時可能也不知道要用什麼類,運行時才知道。比如載入資料庫驅動的時候,你可以直接 new 出來具體的驅動類,但要是換了資料庫呢,還要修改源碼重新打包更新麽?

new com.mysql.jdbc.Driver();

那你可能會說,我多寫幾個 if else 不就行了,類似下麵這樣:

if ( xxx == "mysql") {
    new com.mysql.jdbc.Driver();
else if ( xxx == "redis" ) {
    new com.redis.jdbc.Driver();
else if ( ... ){
}

這樣的問題是,在編譯期就要湊齊所有的 jdbc 連接庫,甭管用不用這些都會被載入到記憶體中,資料庫類型多了會有極大的浪費。
那麼這種情況,就可以用反射來解決,在運行時才去動態的載入對應類。你也可以在配置文件中指明要使用哪種資料庫類,連接不同的資料庫都可以使用這一份程式。

// 反射的方式動態載入類
Class.forName("com.mysql.jdbc.Driver");

三、反射的基本使用

下麵介紹通過反射都能做什麼:

一)獲得 Class 對象

// 1 使用 Class 類的 forName 靜態方法
 Class.forName(driver);

// 2 直接獲取某一個對象的 class
Class<?> cl = int.class;

// 3 調用某個對象的 getClass() 方法
StringBuilder str = new StringBuilder("123");
Class<?> klass = str.getClass();

二)判斷是否為某個類的實例

public static void displayObjectClass(Object o) {
    if (o instanceof Vector)
   		System.out.println("對象是 java.util.Vector 類的實例");
  	else if (o instanceof ArrayList)
   		System.out.println("對象是 java.util.ArrayList 類的實例");
   	else
   		System.out.println("對象是 " + o.getClass() + " 類的實例");
}

三)創建實例

Class<?> c = String.class;
Object str = c.newInstance();

四)獲取方法

getDeclaredMethods() 方法返回類或介面聲明的所有方法,包括公共、保護、預設(包)訪問和私有方法,但不包括繼承的方法。
getMethods() 方法返回某個類的所有公用(public)方法,包括其繼承類的公用方法。
getMethod() 方法返回一個特定的方法,其中第一個參數為方法名稱,後面的參數為方法的參數對應Class的對象。

public class ReflectDemo {
	public static void main(String[] args) throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
	    Class<?> c = MyClass.class;

	    Method[] methods = c.getMethods();
	    Method[] declaredMethods = c.getDeclaredMethods();
	    Method method = c.getMethod("add", int.class, int.class);

        System.out.println("getMethods獲取的方法:");
        for(Method m:methods)
            System.out.println(m);

        System.out.println("getDeclaredMethods獲取的方法:");
        for(Method m:declaredMethods)
            System.out.println(m);
    }
}

class MyClass {
    public int add(int a, int b) {
        return a + b;
    }
    public int sub(int a, int b) {
        return a - b;
    }
}

// 輸出
/*
getMethods獲取的方法:
public int com.shuofxz.basic.ReflectDemo$MyClass.add(int,int)
public int com.shuofxz.basic.ReflectDemo$MyClass.sub(int,int)
public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
public final void java.lang.Object.wait() throws java.lang.InterruptedException
public boolean java.lang.Object.equals(java.lang.Object)
public java.lang.String java.lang.Object.toString()
public native int java.lang.Object.hashCode()
public final native java.lang.Class java.lang.Object.getClass()
public final native void java.lang.Object.notify()
public final native void java.lang.Object.notifyAll()

getDeclaredMethods獲取的方法:
public int com.shuofxz.basic.ReflectDemo$MyClass.add(int,int)
public int com.shuofxz.basic.ReflectDemo$MyClass.sub(int,int)
*/

五)調用方法

當我們從類中獲取了一個方法後,我們就可以用 invoke() 來調用這個方法。

public class ReflectDemo {
	public static void main(String[] args) throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
        Class<?> mc = MyClass.class;
        Object obj = mc.newInstance();
        //獲取methodClass類的add方法
        Method method = mc.getMethod("add", int.class, int.class);
        //調用method對應的方法 => add(1,4)
        Object result = method.invoke(obj, 1, 4);
        System.out.println(result);
    }
}

六)獲取構造器、類的成員變數(欄位)信息

  • 通過 Class 類的 getConstructor 方法得到 Constructor 類的一個實例
  • getFiled:訪問公有的成員變數
  • getDeclaredField:所有已聲明的成員變數,但不能得到其父類的成員變數

四、小結

本篇文章初步介紹了反射機制。讓大家瞭解了反射是什麼,為什麼會有反射這個功能,以及一些基本使用方式。後續文章將會反射的機制和原理做進一步的講解。


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

-Advertisement-
Play Games
更多相關文章
  • 一、前言 最近學習pyqt5中文教程時,最後一個例子製作了一個俄羅斯方塊小游戲,由於解釋的不是很清楚,所以源碼有點看不懂,查找網上資料後,大概弄懂了源碼的原理。 二、繪製主視窗 將主視窗居中,且設置了一個狀態欄來顯示三種信息:消除的行數,游戲暫停狀態或者游戲結束狀態。 class Tetris(QM ...
  • JZ46 把數字翻譯成字元串 描述 有一種將字母編碼成數字的方式:'a'->1, 'b->2', ... , 'z->26'。 現在給一串數字,返回有多少種可能的解碼結果 示例1 輸入: "12" 返回值:2 說明: 2種可能的解碼結果(”ab” 或”l”) 思路 思路: 對於普通數組1-9,解碼方 ...
  • 1、設計想法 原理與之前的串口發送模塊一樣,1位的數據位和8位的數據位再加上1位的停止位。唯一不同的是在接收的時候要考慮到有干擾的情況下,為了避免干擾,我們對每位數據進行多次採樣,按出現概率大的值為該數據位的值。 如果按照通常想法在每bits位中間取值的話,bit3位出現圖中的干擾很有可能會讀出錯誤 ...
  • win11特有的快捷鍵 win鍵就是圖案是windows圖標的那個按鍵 | 作用 | 快捷鍵 | | | | | 打開快速設置,win11是展開音量,wifi,藍牙的設置項,win10也可以用 | win + a | | 打開通知中心和日曆,win10無 | win + n | | 打開投屏,win ...
  • RDP,Remote Desktop Protocol,遠程桌面協議,是一個多通道(mutil-channel)的協議,讓用戶(客戶端或稱“本地電腦”)連上提供微軟終端機服務的電腦(伺服器端或稱“遠程電腦”)。大部分的Windows、Linux、FreeBSD、Mac OS X都有相應的客戶端。服務... ...
  • 1. 判斷本地是否已經安裝MySQL ① 在運行界面輸入services.msc進入服務界面,查看是否有MySQL服務 ② 進入任務管理器,點擊服務看是否有MySQL服務 2. 安裝MySQL(壓縮包版) 1. 下載MySQL社區伺服器(ZIP): MySQL zip下載 點擊No thanks,j ...
  • 本文是 CSS Houdini 之 CSS Painting API 系列第四篇。 現代 CSS 之高階圖片漸隱消失術 現代 CSS 高階技巧,像 Canvas 一樣自由繪圖構建樣式! 現代 CSS 高階技巧,完美的波浪進度條效果! 在上三篇中,我們詳細介紹了 CSS Painting API 是如 ...
  • 因為團隊內部開啟了一個持續的前端代碼質量改進計劃,其中一個專項就是TS類型覆蓋率,期間用到了type-coverage這個倉庫,所以借這篇文章分享一下這個工具,並順便從源碼閱讀的角度來分析一下該工具的源碼,我自己fork了一個倉庫,完成了中文版本的ReadMe文件並對核心代碼添加了關鍵註釋,需要的同 ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...