Java反射的使用和原理詳解
1. 反射是什么?
反射是java語言的一個(gè)特性,它允程序在運(yùn)行時(shí)(注意不是編譯的時(shí)候)來進(jìn)行自我檢查并且對(duì)內(nèi)部的成員進(jìn)行操作。
反射是在運(yùn)行狀態(tài)中,對(duì)于任意一個(gè)類,都能夠知道這個(gè)類的所有屬性和方法,對(duì)于任意一個(gè)對(duì)象,都能夠調(diào)用它的任意方法和屬性,這種動(dòng)態(tài)獲取信息以及動(dòng)態(tài)調(diào)用對(duì)象方法的功能稱為java語言的反射機(jī)制。
一句話總結(jié):反射就是在運(yùn)行時(shí)才知道要操作的類是什么,并且可以在運(yùn)行時(shí)獲取類的完整構(gòu)造,并調(diào)用對(duì)應(yīng)的方法。
2. 為什么要用反射?
Java Reflection功能非常強(qiáng)大,并且非常有用,比如:
- 獲取任意類的名稱、package信息、所有屬性、方法、注解、類型、類加載器等
- 獲取任意對(duì)象的屬性,并且能改變對(duì)象的屬性
- 調(diào)用任意對(duì)象的方法
- 判斷任意一個(gè)對(duì)象所屬的類
- 實(shí)例化任意一個(gè)類的對(duì)象
- 通過反射我們可以實(shí)現(xiàn)動(dòng)態(tài)裝配,降低代碼的耦合度,動(dòng)態(tài)代理等。
3. 怎么使用反射?
一般情況下我們通過反射創(chuàng)建類對(duì)象主要有兩種方式:
- 通過 Class 對(duì)象的 newInstance() 方法
- 通過 Constructor 對(duì)象的 newInstance() 方法
第一種:通過 Class 對(duì)象的 newInstance() 方法。
- Class clz = Class.forName("com.mikechen.reflection.JiaGou");
- JiaGou jg= (JiaGou)clz.newInstance();
第二種:通過 Constructor 對(duì)象的 newInstance() 方法
- Class clz = Class.forName("com.mikechen.reflection.JiaGou");
- Constructor constructor = clz.getConstructor();
- JiaGou jg= (JiaGou)constructor.newInstance();
通過 Constructor 對(duì)象創(chuàng)建類對(duì)象可以選擇特定構(gòu)造方法,而通過 Class 對(duì)象則只能使用默認(rèn)的無參數(shù)構(gòu)造方法,下面的代碼就調(diào)用了一個(gè)有參數(shù)的構(gòu)造方法進(jìn)行了類對(duì)象的初始化。
- Class clz = Class.forName("com.mikechen.reflection.JiaGou");
- Constructor constructor = clz.getConstructor(String.class);
- JiaGou jg= (JiaGou)constructor.newInstance("mikechen的互聯(lián)網(wǎng)架構(gòu)");
接下來我們就可以通過具體的API調(diào)用獲取到詳細(xì)的屬性或者方法等詳細(xì)了。
3.1 獲取類的成員變量的信息
Field[] fields = cls.getDeclaredFields();

3.2 獲得類方法
Method[] methods = cls.getDeclaredMethods();

3.3 獲得構(gòu)造函數(shù)
Constructor[] constructors = cls.getDeclaredConstructors();

這樣通過反射就可以做在運(yùn)行時(shí)獲取類的完整構(gòu)造,并獲得類信息了。

4. 反射工作原理
調(diào)用反射的總體流程如下:
1、當(dāng)我們編寫完一個(gè)Java項(xiàng)目之后,每個(gè)java文件都會(huì)被編譯成一個(gè).class文件。

2、這些class文件在程序運(yùn)行時(shí)會(huì)被ClassLoader加載到JVM中,當(dāng)一個(gè)類被加載以后,JVM就會(huì)在內(nèi)存中自動(dòng)產(chǎn)生一個(gè)Class對(duì)象。

3、通過Class對(duì)象獲取Field/Method/Construcor

我們一般平時(shí)是通過new的形式創(chuàng)建對(duì)象實(shí)際上就是通過這些Class來創(chuàng)建的,只不過這個(gè)class文件是編譯的時(shí)候就生成的,程序相當(dāng)于寫死了給jvm去跑。

反射是什么呢?當(dāng)我們的程序在運(yùn)行時(shí),需要?jiǎng)討B(tài)的加載一些類,這些類可能之前用不到所以不用加載到j(luò)vm,而是在運(yùn)行時(shí)根據(jù)需要才加載。
原來使用new的時(shí)候,需要明確的指定類名,這個(gè)時(shí)候?qū)儆谟簿幋a實(shí)現(xiàn),而在使用反射的時(shí)候,可以只傳入類名參數(shù),就可以生成對(duì)象,降低了耦合性,使得程序更具靈活性。
5. 反射的應(yīng)用場景

舉個(gè)例子我們的項(xiàng)目底層數(shù)據(jù)庫有時(shí)是用mysql,有時(shí)用oracle,需要?jiǎng)討B(tài)地根據(jù)實(shí)際情況加載驅(qū)動(dòng)類,這個(gè)時(shí)候反射就有用了,假設(shè) com.mikechen.java.myqlConnection,com.mikechen.java.oracleConnection這兩個(gè)類我們要用。
這時(shí)候我們在使用 JDBC 連接數(shù)據(jù)庫時(shí)使用 Class.forName()通過反射加載數(shù)據(jù)庫的驅(qū)動(dòng)程序,如果是mysql則傳入mysql的驅(qū)動(dòng)類,而如果是oracle則傳入的參數(shù)就變成另一個(gè)了。
Spring 框架的 IOC(動(dòng)態(tài)加載管理 Bean),Spring通過配置文件配置各種各樣的bean,你需要用到哪些bean就配哪些,spring容器就會(huì)根據(jù)你的需求去動(dòng)態(tài)加載,你的程序就能健壯地運(yùn)行。
還有Spring AOP(動(dòng)態(tài)代理)功能都和反射有關(guān)系。
除此之外還有很多框架:mybatis、dubbo、rocketmq等等都會(huì)用到反射機(jī)制。
到此這篇關(guān)于Java反射的使用和原理詳解的文章就介紹到這了,更多相關(guān)Java反射內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java報(bào)錯(cuò):java.lang.UnsatisfiedLinkError問題的解決辦法
在Java開發(fā)中,java.lang.UnsatisfiedLinkError是一種與本地方法調(diào)用相關(guān)的常見異常,本文將詳細(xì)分析這一異常的背景、可能的原因、錯(cuò)誤代碼示例、正確代碼示例,以及編寫代碼時(shí)需要注意的事項(xiàng),需要的朋友可以參考下2024-09-09
springboot整合curator實(shí)現(xiàn)分布式鎖過程
這篇文章主要介紹了springboot整合curator實(shí)現(xiàn)分布式鎖過程,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-05-05
Springboot使用jxls實(shí)現(xiàn)同sheet多個(gè)列表展示
這篇文章主要介紹了Springboot使用jxls實(shí)現(xiàn)同sheet多個(gè)列表展示,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-08-08
基于Comparator對(duì)象集合實(shí)現(xiàn)多個(gè)條件按照優(yōu)先級(jí)的比較
這篇文章主要介紹了基于Comparator對(duì)象集合實(shí)現(xiàn)多個(gè)條件按照優(yōu)先級(jí)的比較,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-07-07

