Java反射詳細介紹

?的反射(Reflection)是一種強大的機制,允許程序在運行時動態獲取類的信息、操作類的成員(屬性、方法、構造器),甚至修改類的行為。它是框架開發(如 Spring、MyBatis)、單元測試工具(如 JUnit)的核心技術之一。

一、認識反射

反射的核心是在運行時獲取類的元數據(類的結構信息),突破了傳統編程 “編譯時確定類型” 的限制。例如:

運行時判斷任意對象的所屬類;

運行時構造任意類的對象;

運行時獲取 / 修改類的屬性、調用類的方法(包括私有成員)

運行時處理注解。

二、Class 類詳解

在 ?中,Class?類是反射的入口。每個類被加載到 JVM 時,會生成唯一的?Class?對象,存儲該類的所有元數據(如類名、父類、接口、屬性、方法等)。

2.1 獲取 Class 對象的 3 種方式

// 方式1:通過 類名.class(編譯時已知類)

Class<String> stringClass = String.class;

// 方式2:通過 對象.getClass()(已知對象)

String str = "hello";Class<? extends String> strClass = str.getClass();

// 方式3:通過 Class.forName("全限定類名")(動態加載,最常用)

try {

Class<?> userClass = Class.forName("com.example.User"); }

catch (ClassNotFoundException e) {

e.printStackTrace();

}

2.2 Class 類的常用方法

方法

說明

getName()

獲取類的全限定名(如?.lang.String)

getSimpleName()

獲取類的簡單名(如?String)

getSuperclass()

獲取父類的?Class?對象

getInterfaces()

獲取實現的接口數組

getFields()

獲取所有公有屬性(含父類)

getDeclaredFields()

獲取所有屬性(含私有,不含父類)

getMethods()

獲取所有公有方法(含父類)

getDeclaredMethods()

獲取所有方法(含私有,不含父類)

getConstructors()

獲取所有公有構造器

getDeclaredConstructors()

獲取所有構造器(含私有)

三、Class 類與多態

多態的本質是 “父類引用指向子類對象”,但反射可以突破多態的表象,直接操作子類或父類的真實信息。

示例:通過反射獲取多態對象的真實類信息
假設有繼承關系:Animal(父類)→?Dog(子類)。

class?Animal?{

?public?void?eat()?{

?System.out.println("Animal eat");

? }?

}

class?Dog?extends?Animal?{?

@Override?

public?void?eat()?{?

System.out.println("Dog eat");?

}

?}

public?class?PolymorphismDemo?{

????public?static?void?main(String[]?args)?{

????????Animal?animal =?new?Dog();?// 多態:父類引用指向子類對象

????????

????????// 傳統方式調用方法(表現多態)

????????animal.eat();?// 輸出:Dog eat

????????

????????// 反射獲取真實類的信息

????????Class<?>?realClass =?animal.getClass();?

????????System.out.println("真實類名:"?+?realClass.getSimpleName());?// 輸出:Dog

????????

????????// 反射調用父類的方法(繞過多態)

????????try?{

????????????Method?parentEat =?realClass.getSuperclass().getMethod("eat");

????????????parentEat.invoke(animal);?// 輸出:Animal eat(調用了父類的原始方法)

????????}?catch?(Exception?e)?{

????????????e.printStackTrace();

????????}

}

}

輸出結果:

Dog eat

真實類名:Dog

Animal eat

四、反射創建類對象

通過反射可以動態創建類的實例,即使類的構造器是私有的(需設置?setAccessible(true))。

4.1 無參構造創建對象

class?User?{

????private?String?name;

????public?User()?{?System.out.println("無參構造被調用");?}

public?User(String?name)?{?this.name =?name;?}

}

public?class?CreateObjectDemo?{

????public?static?void?main(String[]?args)?{

????????try?{

????????????// 1. 獲取User的Class對象

????????????Class<?> userClass = Class.forName("com.example.User");

????????????

????????????// 2. 通過無參構造創建實例(等價于 new User())

????????????User?user =?(User)?userClass.getDeclaredConstructor().newInstance();

????????}?catch?(Exception?e)?{

????????????e.printStackTrace();

????????}

}

}

輸出:無參構造被調用

4.2 有參構造創建對象

public?class?CreateObjectWithArgsDemo?{

????public?static?void?main(String[]?args)?{

????????try?{

????????????Class<?>?userClass =?Class.forName("com.example.User");

????????????

????????????// 獲取有參構造器(參數類型為String)

????????????Constructor<?>?constructor =?userClass.getDeclaredConstructor(String.class);

????????????

????????????// 創建實例(等價于 new User("xxx"))

????????????User?user =?(User)?constructor.newInstance("xxx");

????????}?catch?(Exception?e)?{

????????????e.printStackTrace();

????????}

}

}

4.3 私有構造器創建對象(突破訪問限制)

class?SecretClass?{

private?SecretClass()?{?System.out.println("私有構造被調用");?

}

}

public?class?CreatePrivateObjectDemo?{

????public?static?void?main(String[]?args)?{

????????try?{

????????????Class<?>?secretClass =?Class.forName("com.example.SecretClass");

????????????

????????????// 獲取私有構造器

????????????Constructor<?>?privateConstructor =?secretClass.getDeclaredConstructor();

????????????

????????????// 允許訪問私有成員(關鍵!)

????????????privateConstructor.setAccessible(true);

????????????

????????????// 創建實例

????????????SecretClass?instance =?(SecretClass)?privateConstructor.newInstance();

????????}?catch?(Exception?e)?{

????????????e.printStackTrace();

????????}

}

}

輸出:私有構造被調用

五、反射調用類方法

通過反射可以調用任意對象的方法(包括私有方法),甚至可以調用未實現的方法(動態代理的基礎)。

5.1 調用公有方法

class?Calculator?{

public?int?add(int?a,?int?b)?{?return?a +?b;?}

}

public?class?InvokeMethodDemo?{

????public?static?void?main(String[]?args)?{

????????try?{

????????????Calculator?calc =?new?Calculator();

????????????Class<?>?calcClass =?calc.getClass();

????????????

????????????// 獲取add方法(參數類型為int, int)

????????????Method?addMethod =?calcClass.getMethod("add",?int.class,?int.class);

????????????

????????????// 調用方法(等價于 calc.add(3, 5))

????????????int?result =?(int)?addMethod.invoke(calc,?3,?5);

????????????System.out.println("計算結果:"?+?result);?// 輸出:8

????????}?catch?(Exception?e)?{

????????????e.printStackTrace();

????????}

}

}

5.2 調用私有方法(突破訪問限制)

class?PrivateMethodClass?{

????private?String?formatName(String?name)?{

????????return?"Hello, "?+?name +?"!";

}

}

public?class?InvokePrivateMethodDemo?{

????public?static?void?main(String[]?args)?{

????????try?{

????????????PrivateMethodClass?obj =?new?PrivateMethodClass();

????????????Class<?>?clazz =?obj.getClass();

????????????

????????????// 獲取私有方法(方法名、參數類型)

????????????Method?privateMethod =?clazz.getDeclaredMethod("formatName",?String.class);

????????????

????????????// 允許訪問私有成員

????????????privateMethod.setAccessible(true);

????????????

????????????// 調用方法(等價于 obj.formatName("xxx"))

????????????String?result =?(String)?privateMethod.invoke(obj,?"xxx");

????????????System.out.println(result);?// 輸出:Hello, xxx!

????????}?catch?(Exception?e)?{

????????????e.printStackTrace();

????????}

}

}

六、反射修改類屬性

通過反射可以直接修改對象的屬性值(包括私有屬性),甚至繞過 setter 方法。

6.1 修改公有屬性

class?Book?{

public?String?title =?"默認書名";

}

public?class?ModifyFieldDemo?{

????public?static?void?main(String[]?args)?{

????????try?{

????????????Book?book =?new?Book();

????????????Class<?>?bookClass =?book.getClass();

????????????

????????????// 獲取公有屬性title

????????????Field titleField = bookClass.getField("title");

????????????

????????????// 修改屬性值(等價于 book.title = "反射詳解")

????????????titleField.set(book, "反射詳解");

????????????

????????????System.out.println(book.title);?// 輸出:反射詳解

????????}?catch?(Exception?e)?{

????????????e.printStackTrace();

????????}

}

}

6.2 修改私有屬性(突破訪問限制)

class?User?{

????private?String?password =?"123456";}

public?class?ModifyPrivateFieldDemo?{

????public?static?void?main(String[]?args)?{

????????try?{

????????????User?user =?new?User();

????????????Class<?>?userClass =?user.getClass();

????????????

????????????// 獲取私有屬性password

????????????Field passwordField = userClass.getDeclaredField("password");

????????????

????????????// 允許訪問私有成員

????????????passwordField.setAccessible(true);

????????????

????????????// 修改屬性值(等價于 user.password = "new_password")

????????????passwordField.set(user, "new_password");

????????????

????????????// 驗證修改結果

????????????System.out.println("新密碼:"?+?passwordField.get(user));?// 輸出:new_password

????????}?catch?(Exception?e)?{

????????????e.printStackTrace();

????????}

}

}

七、類加載器

類加載器(Class Loader)負責將?.class?文件加載到 JVM 中,生成對應的?Class?對象。 采用雙親委派模型,確保類的唯一性和安全性。

7.1 類加載器的層級

引導類加載器(Bootstrap Class Loader):加載 JDK 核心類(如?.lang.*),由 C++ 實現,無法通過 ?代碼獲取。

擴展類加載器(Extension Class Loader):加載?jre/lib/ext?目錄下的 JAR 包。

應用類加載器(Application Class Loader):加載用戶項目中的類(classpath?下的類)。

7.2 示例:查看類的加載器

public?class?ClassLoaderDemo?{

????public?static?void?main(String[]?args)?{

????????// 獲取String類的加載器(引導類加載器,輸出null)

????????ClassLoader stringLoader =?String.class.getClassLoader();

????????System.out.println("String類的加載器:"?+?stringLoader);?// 輸出:null

????????

????????// 獲取當前類的加載器(應用類加載器)

????????ClassLoader selfLoader = ClassLoaderDemo.class.getClassLoader();

????????System.out.println("當前類的加載器:"?+?selfLoader);?

????????// 輸出:sun.misc.Launcher$AppClassLoader@18b4aac2

????????

????????// 獲取應用類加載器的父加載器(擴展類加載器)

????????ClassLoader parentLoader = selfLoader.getParent();

????????System.out.println("父加載器:"?+?parentLoader);?

????????// 輸出:sun.misc.Launcher$ExtClassLoader@1b6d3586

}

}

7.3 雙親委派模型的作用

當加載一個類時,類加載器會先委托父類加載器嘗試加載,直到引導類加載器。如果父類無法加載,才由當前類加載器加載。
好處:避免重復加載,防止核心類被篡改(如自定義?.lang.String?不會被加載)。

反射是 ?的 “動態之魂”,但過度使用會降低代碼可讀性和安全性(如破壞封裝性)。實際開發中,框架(如 Spring)已封裝了反射的復雜操作,開發者只需理解原理即可。建議結合源碼(如 Spring 的?BeanFactory)深入學習反射的應用。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/80894.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/80894.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/80894.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

c語言第一個小游戲:貪吃蛇小游戲05

貪吃蛇脫韁自動向右走&#xff1a;脫韁的野蛇 #include <curses.h> #include <stdlib.h> struct snake{ int hang; int lie; struct snake *next; }; struct snake *head; struct snake *tail; void initNcurse() { initscr(); keypad(stdscr,1); } int …

react-diff-viewer 如何實現語法高亮

前言 react-diff-viewer 是一個很好的 diff 展示庫&#xff0c;但是也有一些坑點和不完善的地方&#xff0c;本文旨在描述如何在這個庫中實現自定義語法高亮。 Syntax highlighting is a bit tricky when combined with diff. Here, React Diff Viewer provides a simple rend…

coco數據集mAP評估

0 coco數據集劃分說明 1 用yolo自帶的評估 from ultralytics import YOLOmodel YOLO("../spatial-perception/checkpoints/yolo11n.pt")metrics model.val(data"./coco.yaml", save_jsonTrue) ## save_json為True,可以把預測結果存成json文件&#xff…

sensitive-word-admin v2.0.0 全新 ui 版本發布!vue+前后端分離

前言 sensitive-word-admin 最初的定位是讓大家知道如何使用 sensitive-word&#xff0c;所以開始想做個簡單的例子。 不過秉持著把一個工具做好的原則&#xff0c;也收到很多小伙伴的建議。 v2.0.0 在 ruoyi-vue&#xff08;也非常感謝若依作者多年來的無私奉獻&#xff09…

好消息!PyCharm 社區版現已支持直接選擇 WSL 終端為默認終端

在過去&#xff0c;PyCharm 社區版雖然提供了鏈接 Windows 子系統 Linux&#xff08;WSL&#xff09;終端的能力&#xff0c;但用戶無法在設置中直接指定 WSL 為默認終端&#xff0c;這一功能僅限于專業版使用者。 而現在&#xff0c;在 PyCharm 2025.1.1 版本中&#xff0c;Je…

【Redis】string 字符串

文章目錄 string 字符串常用命令設置和獲取setgetmget & mset 計數操作incr & incrbydecr & decrbyincrbyfloat 字符串操作appendstrlengetrangesetrange 應用場景 string 字符串 關于 Redis 的字符串&#xff0c;有幾點需要注意 Redis 所有的 key 的類型都是字符…

本地部署firecrawl的兩種方式,自托管和源碼部署

網上資料很多 AI爬蟲黑科技 firecrawl本地部署-CSDN博客 源碼部署 前提條件本地安裝py&#xff0c;node.js環境,嫌棄麻煩直接使用第二種 使用git或下載壓縮包 git clone https://github.com/mendableai/firecrawl.git 設置環境參數 cd /firecrawl/apps/api 復制環境參數 …

(三)毛子整潔架構(Infrastructure層/DapperHelper/樂觀鎖)

文章目錄 項目地址一、Infrastructure Layer1.1 創建Application層需要的服務1. Clock服務2. Email 服務3. 注冊服務 1.2 數據庫服務1. 表配置Configurations2. Respository實現3. 數據庫鏈接Factory實現4. Dapper的DataOnly服務實現5. 所有數據庫服務注冊 1.3 基于RowVersion的…

uni-app微信小程序登錄流程詳解

文章目錄 uni-app微信小程序登錄流程實戰詳解微信小程序登錄流程概述1. 獲取登錄憑證&#xff08;code&#xff09;2. 發送登錄請求3. 保存登錄態4. 登錄狀態管理5. 應用登錄狀態請求攔截器中添加 token自動登錄頁面路由守衛 使用 Vuex 集中管理登錄狀態登錄組件示例登錄流程最…

GUC并發編程和SpringCloud,二者之間的關系

一.提問 我認為&#xff0c;Java開發中&#xff0c;如果項目的每一個小模塊需要不同人員并行開發時&#xff0c;就需要使用SpringCloud&#xff1b;如果要解決系統用戶激增&#xff0c;就是用GUC并發編程。 這個說法對么&#xff1f; 二.解答 你的理解部分正確&#xff0c;但不…

在 Vue 3 中使用 canvas-confetti 插件

&#x1f389; 在 Vue 3 中使用 canvas-confetti 插件 canvas-confetti 是一個輕量、無依賴的 JavaScript 動畫庫&#xff0c;用于在網頁上展示彩帶、慶祝動畫。非常適合用于抽獎、支付成功、活動慶祝等場景。 本教程將指導你如何在 Vue 3 項目中集成并使用該插件。 &#x1…

深入解析Spring Boot項目目錄結構:從新手到規范實踐

一、標準項目結構全景圖 典型的Spring Boot項目&#xff08;Maven構建&#xff09;目錄結構如下&#xff1a; my-spring-project/ ├── src/ │ ├── main/ │ │ ├── java/ # 核心代碼 │ │ │ └── com/ │ │ │ └── exa…

【C語言】宏經典練習題,交換奇偶位

交換奇偶位 寫一個宏&#xff0c;可以將一個整數的二進制位的奇數位和偶數位交換。 #define Swap(x) x(((x&0x55555555)<<1)((x&0xaaaaaaaa)>>1)) int main() {int a 10;Swap(a);printf("%d\n", a);return 0; } 寫宏的思路&#xff1a; 假設…

VSCode-插件:codegeex:ai coding assistant / 清華智普 AI 插件

一、官網 https://codegeex.cn/ 二、vscode 安裝插件 點擊安裝即可&#xff0c;無需復雜操作&#xff0c;國內軟件&#xff0c;無需科學上網&#xff0c;非常友好 三、智能注釋 輸入 // 或者 空格---后邊自動出現注釋信息&#xff0c;&#xff0c;按下 Tab 鍵&#xff0c;進…

FFmpeg 與 C++ 構建音視頻處理全鏈路實戰(三)—— FFmpeg 內存模型

經過前面文章的 FFmpeg 編程實踐&#xff0c;相信你已經對AVPacket和AVFrame這兩個核心結構體不再陌生。當我們編寫代碼時&#xff0c;頻繁調用unref系列 API 釋放內存的操作&#xff0c;或許讓你心生疑惑&#xff1a;這些函數究竟是如何實現內存釋放的&#xff1f;又該在何時準…

c 中的哈希表

哈希是一種可以接受各種類型、大小的輸入&#xff0c;輸出一個固定長度整數的過程。你可以將哈希理解成一種特殊的映射&#xff0c;哈希映射&#xff0c;將一個理論無限的集合A映射到有限整數集合B上。 哈希函數&#xff1a;哈希函數是哈希過程的核心&#xff0c;它決定了哈希映…

【一次成功!】Ubuntu22.04安裝cartographer

之前在ubuntu20.04上成功安裝cartographer&#xff0c;但是翻遍全網都沒找到官方的22.04安裝教程&#xff0c;然后找到小魚的&#xff0c;試了一下&#xff0c;一次成功&#xff0c;連接如下&#xff1a; gd2l-ros2/docs/humble/chapt10/get_started/2.Carto介紹及安裝.md at …

【WPF】Opacity 屬性的使用

在WPF&#xff08;Windows Presentation Foundation&#xff09;中&#xff0c;Opacity 屬性是定義一個元素透明度的屬性&#xff0c;其值范圍是從 0.0&#xff08;完全透明&#xff09;到 1.0&#xff08;完全不透明&#xff09;。由于 Opacity 是在 UIElement 類中定義的&…

8天Python從入門到精通【itheima】-6~10

目錄 7節-開發出第一個Python程序: 1.在cmd窗口寫下第一個最簡單的程序:Hello World!!! 9節: 1.如何卸載python: 2.報錯:不是可運行的程序 ?編輯 3.報錯:無法初始化設備PRN: 4.報錯:語法錯誤——非法的字符 10節-python解釋器: 1.python解釋器的原理: 2.解…

Mac 3大好用的復制粘貼管理工具對比

剪貼板管理器是查看復制粘貼歷史記錄的工具&#xff0c;幾乎是每個蘋果電腦用戶必備工具。市面上的工具很多&#xff0c;我結合了功能豐富、設計簡潔、交互便利整理了目前3款頭部剪貼板應用 Paste、PasteNow、PasteMe。 Paste 優勢&#xff1a;老牌剪切板應用&#xff0c;功能…