學Java反射,看這篇就夠了 | 原力計劃

2021-02-19 程序人生

作者 | P6級程式設計師

責編 | 王曉曼

出品 | CSDN博客

首先學習反射之前,我要提出疑問:

反射是個什麼東西?它是用來做什麼的?平時的應用場景有哪些?為啥要用它?它有什麼優缺點?它的工作原理是什麼?我怎麼使用它?

這麼多的問題,這是在挑釁啊,既然如此,那麼我想起來宮本的那句:想挑戰的,一個一個來。先解決第一個問題。

 

此為何物

 

百度看了看反射的介紹:

超過二秒後,我表示看不下去了,就不能簡單點嗎?這是給人看的嗎?像我這種人,是看不下去的。

我們來一句話定義反射:

反射就是把 Java 類中的各種成分映射成一個個的 Java 對象。

不理解這句話什麼意思?沒關係,在我百度了幾分鐘後,找到三種解釋:

解釋一:一個類有:成員變量、方法、構造方法、包等等信息,利用反射技術可以對一個類進行解剖,把各個組成部分映射成一個個對象。

解釋二:說反射先聊聊正射。

反射機制是不知道類是什麼樣的,它是根據類的類名,去獲取一個實例,然後根據方法名去執行方法。好比說,一般情況下畫一隻老虎,問我得先知道老虎長什麼樣子才能畫出來;有了反射機制,我只要知道「老虎」這個名字就能畫出來。

解釋三:假如我們有兩個程式設計師,一個程式設計師在寫程序的時候,需要使用第二個程式設計師所寫的類,但第二個程式設計師並沒完成他所寫的類。那麼第一個程式設計師的代碼能否通過編譯呢?這是不能通過編譯的。利用Java反射的機制,就可以讓第一個程式設計師在沒有得到第二個程式設計師所寫的類的時候,來完成自身代碼的編譯。

解釋四:如果你是方法,快遞員是虛擬機。快遞員通過地址查地圖找你的叫反射調用。直接去找你的叫直接調用。

現在我們基本已經了解什麼是反射了,接著需要將第二個問題搞定。

 

該物用途

 

接著百度:

 用途太多,概念也很多,我需要一句話就可以解釋它的作用或者用途:

反射可以賦予jvm動態編譯的能力。

看到又出現一個詞,動態編譯,來我們來嘮嘮這個詞。

Java中編譯類型有兩種:

如果不理解,那麼給個業務場景幫助你理解:比如開發一個閱讀器,支持txt,pdf,doc三種格式。我們把讀txt,讀pdf,讀doc定義為三個功能模塊。

顯然,動態編譯1速度快,2節省了系統資源,3利於今後拓展。

那麼這個JVM動態編譯常用的場景有哪些呢?或者說反射的使用場景(用途)有哪些?此物的用途?

場景一:在日常的第三方應用開發過程中,經常會遇到某個類的某個成員變量、方法或是屬性是私有的或是只對系統應用開放,這時候就可以利用Java的反射機制通過反射來獲取所需的私有成員或是方法。

場景二:當我們在使用IDE(如Eclipse,IDEA)時,當我們輸入一個對象或類並想調用它的屬性或方法時,一按點號,編譯器就會自動列出它的屬性或方法,這裡就會用到反射。

場景三:反射最重要的用途就是開發各種通用框架。很多框架(比如Spring)都是配置化的(比如通過XML文件配置JavaBean,Action之類的),為了保證框架的通用性,它們可能需要根據配置文件加載不同的對象或類,調用不同的方法。

為啥要用它?它有什麼優缺點?

 

Java的反射機制就是增加程序的靈活性,解耦。反射就是一種機制,可以讓你僅知道類的名字的情況下,可以了解整個類的內部的結構,並且訪問內部的成員和方法等。

解釋:對於大型的軟體,一個大公司的各個小組都有自己的分工,去實現不同的模塊,那麼各個小組之間如何協作就非常關鍵。例如A小組完成IPolicy接口的實現,而B小組需要使用A的實現,這時候就可以使用反射機制,B小組完全不用知道IPolicy是如何實現的,只需要知道實現後的類名即可,或者說,類名完全保存在一個xml或者屬性中,由A小組去填充,這樣B小組的代碼看上去就和A毫無瓜葛。

因此反射在一般框架中使用較多。因為框架要適用更多的情況。對靈活性要求較高。

優勢:

缺點:

相較直接調用在量大的情景下反射性能下降。

存在一些內部暴露和安全隱患。

針對它的缺點,我們聊聊反射到底慢在哪些地方

反射的工作原理?反射技術的組成部分?

 

萬物皆對象,我們定義的類其實從面向對象的角度來分析,它其實也是一個具體的對象,它是一個描述類的實例。描述這個類中有哪些屬性,行為等等內容.。我們可以通過定義類,來描述一組具有相同屬性,行為的實例對象。比如我們創建Person 類。

Class Person {
    String ID;
    int age;Seven
    void talk(){

    }
}

我們可以基於這個類創建具體不同身份證號和姓名的 Person 實例(new Person)。每一個實例都具有身份證號,年齡,說話的行為。通過上面的簡單案例,我們可以這麼理解在Java 語言中Class 的定義,是創建對象的統一模板。

那麼我們可以思考這樣一個問題,既然不管是 Java 語言默認的類還是我們自定義創建的類都 是為了創建具有相同行為屬性的對象的模板。

那麼每一個類我們在定義的時候,是不是也可以抽取共性的東西,比如,每一個類都有包名,屬性定義,行為(方法),構造器等等。

那麼既然每一個類都會具備這樣的內容,那麼這些類對象實例,應該也可以抽取成一個公有的模板,用於創建類對象實例的模板。所以在java 中,這個類定義的創建模板就是我們 java 語言中的 java.lang.Class 類。在 Class 的模板中,我們也可以找到大家耳熟能詳的模板類如Method,Constructor,Field...

深入 Class 內部

通過上面的內容,我們已經了解到我們創建的每一個自定義的Class實例都是基於他的模板類java.lang.Class 類。在大家每一個編寫的類實例中,都會定義這個類的包名,類名,訪問域,特徵符,構造器,欄位,函數,父類,接口等等內容。這些內容在我們的 Class 類中都提供了對應的獲取方法進行獲取。

如何使用?

 

1、反射-基本信息操作

intmodifier = clazz.getModifiers(); //獲取類的修飾符

Packagepackage= clazz.getPackage();//獲取類的包名

StringfullClassName = clazz.getName();//獲取類的全路徑名稱

StringsimpleClassName = clazz.getSimpleName();//獲取類的簡單名稱

ClassLoaderclassLoader = clazz.getClassLoader();//獲取類的類加載器

Class[]interfacesClasses = clazz.getInterfaces();//獲取類實現的接口列表

Classfc= clazz.getSuperclass();//獲取類的父類

Annotation[]annotations= clazz.getAnnotations(); //獲取類的註解列表

2、反射-欄位操作

Field[]fields = clazz.getFields();//獲取類中所有的公有欄位包含繼承

Field[]declaredFields=clazz.getDeclaredFields();//獲取類中定義的欄位 內部

FieldnameField=clazz.getField("name");//獲取指定名稱的公有欄位

FieldlikeDescField=clazz.getDeclaredField("likeDesc");//獲取指定名稱類中定義的欄位

intmodifersFiled = likeDescField.getModifiers();//獲取欄位的修飾

nameField.setAccessible(true);//指定欄位強制訪問

nameField.set(person,"小皮皮");//成員欄位賦值(需指定對象)

descriptionField.set(null,"沒有結婚的都是男孩!");//靜態欄位賦值

3、反射-方法操作

Method[]methods = clazz.getMethods();//獲取類中所有的公有方法繼承

Method[]declaredMethods = clazz.getDeclaredMethods();//獲取類中定義的方法

MethodtalkMethod = clazz.getMethod("talk", String.class);//獲取類中指定名稱和參數的公有方法

MethodpugMethod = clazz.getDeclaredMethod("pickUpGirls") //獲取類中定義指定名稱和參數的方法

intmodifers = pugMethod .getModifiers();//獲取方法的修飾符

talkMethod.invoke(boy,"ILOVE SEVEN");//指定對象進行成員方法的調用

pugMethod.setAccessible(true);//指定方法的強制訪問

pickUpGirlsMethod.invoke(null);//靜態方法的調用

4、反射-構造器操作

Constructor[]cons = clazz.getConstructors();//獲取類中所有的公有構造器

Constructor[]cons = clazz.getDeclaredConstructors();//獲取類中所有的構造器

ConstructorconNoParam= clazz.getDeclaredConstructor();//獲取類中無參的構造器

Constructorcon= clazz.getDeclaredConstructor(String.class,String.class); //獲取類中有參構造

intmodifers = con.getModifiers();//獲取構造器的修飾符

conNoParam.newInstance();//構造器實例對象

con.setAccessible(true);//指定方法的強制訪問

con.newInstance('abc','def');//有參構造調用

class.newInstacne();//class直接調用默認無參構造

舉一反三

 

疑問一:現在我們基本解決上面提出的幾個問題了,有了一個基本的了解之後,有沒有想起我們常常被面試的時候,問到的Spring框架IOC控制反轉,是不是跟反射有那麼一些關聯?或者說SpringIOC容器它是怎麼做到控制反轉的?

疑問二:僅知道類的名字的情況下,可以了解整個類的內部的結構,並且訪問內部的成員和方法等。那麼針對私有的一些方法,或者構造器,豈不是可以破壞它,比如說:通過反射機制可以破壞單例模式,它為啥可以做到這一點的?通過反射機制可以破壞單例模式

版權聲明:本文為CSDN博主「P6級程式設計師」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處連結及本聲明。

原文連結:https://blog.csdn.net/java_programmer_liao/article/details/106013181

6月2日20:00,CSDN 創始人&董事長、極客幫創投創始合伙人蔣濤攜手全球頂級開源基金會主席、董事,聚焦中國開源現狀,直面開發者在開源技術、商業上的難題,你絕不可錯過的開源巔峰對談!立即免費圍觀

更多精彩推薦

☞大佬 Zed 玩轉跨界:不會繪畫的音樂家不是好程式設計師

☞航拍高手、吉他十級,6500+Star 開源項目作者,後浪程式設計師給力!

☞面試官:你的 SQL 一般有幾個 join?| 原力計劃

☞基於深度學習和傳統算法的人體姿態估計,技術細節都講清楚了

☞面試中遇到這 3 個SQL問題,最容易掉坑裡!

☞好撲科技結合區塊鏈行業發展趨勢,重磅推出「好撲區塊鏈合伙人」計劃

點擊閱讀原文,精彩繼續。

相關焦點

  • Java基礎之反射篇
    Java基礎之反射篇「Hello,大家好!我是老醜。今天給大家帶來的知識點是反射」1. 反射是什麼?反射(Reflection),它允許在運行中的Java程序獲取自身的信息,並且可以操作類或者對象的內部屬性。2. 反射可以做什麼?3.
  • Java反射是什麼?看這篇絕對會了!
    反射是java語言的一個特性,它允程序在運行時(注意不是編譯的時候)來進行自我檢查並且對內部的成員進行操作。例如它允許一個java的類獲取他所有的成員變量和方法並且顯示出來。Java 的這一能力在實際應用中也許用得不是很多,但是在其它的程序設計語言中根本就不存在這一特性。例如,Pascal、C 或者 C++ 中就沒有辦法在程序中獲得函數定義相關的信息。
  • Java 反射,這篇寫的很透徹!
    下面我們會圍繞著這幾個問題展開:一、反射機制是什麼?反射是什麼?什麼是反?什麼是正射?<init>() at java.lang.Class.getConstructor0(Class.java:3082) at java.lang.Class.newInstance(Class.java:412) ... 2 more這是因為我們重寫了構造方法,而且是有參構造方法,如果不寫構造方法
  • java如何通過反射操作欄位
    java方法還可以這樣調用》、《我照樣要訪問》這三篇文章,描述了通過java反射創建對象以及調用方法,有興趣的朋友可以翻閱一下。今天我再來寫寫怎麼通過反射操作欄位吧。老規矩,先上我們要操作的類的代碼。這個demo類比較簡單,一個非靜態的欄位name,一個靜態的欄位staticName,都賦值了初始值。
  • Java反射機制深入詳解
    一.概念反射就是把Java的各種成分映射成相應的Java類。Class類的構造方法是private,由JVM創建。反射是java語言的一個特性,它允程序在運行時(注意不是編譯的時候)來進行自我檢查並且對內部的成員進行操作。例如它允許一個java的類獲取他所有的成員變量和方法並且顯示出來。
  • Java基礎教程:java反射機制教程
    一、反射概念 在正式講解反射之前,為了很好的去理解它我們先從一個案例說起。請看下面的代碼: 這時候java語言在設計的時候為我們提供了一個機制,就是反射機制,他能夠很方便的去解決我們的問題。
  • 8千字java反射乾貨|java反射精講
    java反射機制精講目錄1. 反射機制的概念2. 反射的基礎Class類3. 反射的用法4.反射的應用示例反射機制的概念:在運行狀態中,對於任意一個類,都能夠獲取到這個類的所有屬性和方法,對於任意一個對象,都能夠調用它的任意一個方法和屬性(包括私有的方法和屬性),這種動態獲取的信息以及動態調用對象的方法的功能就稱為java語言的反射機制。反射被視為動態語言的關鍵。簡單來說反射就是java的各種成分映射成對應的java類。
  • Java反射,泛型在Json中的運用
    最近項目中遇到了Json數據自動獲取的功能,不然令人想起java的反射,已經很長時間沒複習java了正好一塊連java的這一塊內容一起過一遍。java中的反射無疑就相當於java開發者的春天,在眾多的框架中也能看到它的身影,可以在運行時檢查類,接口、變量和方法等信息,可以實例化調用方法以及設置變量值等。本文主要以代碼的形式直接將反射,泛型的運用展現出來。java中的反射首先新建一個基礎類Author。
  • 你有真正理解 Java 的類加載機制嗎?|原力計劃
    如果下面這道面試題都做對了,那沒錯了,這篇文章你就不用看了,真的。這篇文章將通過對Java類加載機制的講解,讓各位熟練理解Java類的加載機制。我為什麼要用這些面試題作為這篇文章的一部分?因為關於學習有一定的方法,你可以設想一下,如果博主不涉及並分析這幾個面試題,你還有耐心看到這裡嗎?小白槓精童鞋說有......好的,就算有,大篇大篇的理論各位扣心自問,能掌握所有知識嗎?小白槓精童鞋說說能......額,就算能,那你能保證光記理論一個月不遺忘嗎?小白槓精童鞋說可以......我特麼一老北京布鞋過去頭給你打歪(我這暴脾氣我天)。
  • Java面試高頻考點:反射機制使用大全
    作為一個Java開發工程師,在面試的過程中,反射機制也是經常會被問到的一個問題。例如Spring的IOC實現機制,其底層都是依賴於java的反射機制,因此,這是一個非常重要的知識點。對於初學java的同學來說,掌握其使用方法很有必要。
  • Java枚舉深度解讀,看這篇就夠了
    沒錯,這是 jdk 5.0之前的痛點,為了解決實例數量固定,便於維護這些問題,在jdk 5.0之後更新Enum枚舉類解決了這個問題。那在jdk 5.0之前官方是怎麼做的呢?難道需要我們一個個去記住 Calendar 的數字?
  • Java代碼審計基礎之反射
    以便後面列印輸出這就是一個簡單的 Java 命令執行並回顯結果。我們可以看到主要調用了 Runtime.getRuntime().exec那麼我們要如何通過反射的方式進行調用呢?反射調用 Runtime.getRuntime().exec第一種方式,通過強行反射私有構造方法,用 Runtime 實例化進行反射這裡有一個小坑,Runtime的構造函數是私有的:
  • Java反射機制,速度提高1000倍
    以下為譯文:幾個星期前,我想讓我的代碼運行快1000倍,同時不改變複雜度,正如標題所說的,使用Java反射機制,可以讓代碼運行得更快。首先來解釋一下為什麼會首先使用反射機制。我有一個接口(表示一個樹節點)和一個實現這個接口的大量類(100+)。訣竅在於,樹是異構的,每個節點類型可以有不同數量的子節點,或者以不同的方式存儲它們。
  • Java 基礎與提高幹貨系列—Java 反射機制
    正文Java反射機制定義Java反射機制是指在運行狀態中,對於任意一個類,都能夠知道這個類的所有屬性和方法;對於任意一個對象,都能夠調用它的任意一個方法和屬性;這種動態獲取的信息以及動態調用對象的方法的功能稱為java語言的反射機制。用一句話總結就是反射可以實現在運行時可以知道任意一個類的屬性和方法。
  • 阿里P8教你Java註解與反射
    使用反射基本上是一種解釋操作,我們可以告訴JVM,我們想要做什麼然後它滿足我們的要求,這類操作總是慢於直接執行相同的操作。5.3 Java反射相關的主要APIjava.lang.Class:代表一個類java.lang.reflect.Method:代表類的方法java.lang.reflect.Field:代表類的成員變量java.lang.reflect.Constructor:代表類的構造器…5.4 Class類通過Class對象可以得知某個類的屬性,方法,構造器,註解,以及實現了哪些接口等等信息
  • Java 反射機制你還不會?那怎麼看 Spring 源碼?
    反射就是把Java類中的各種成分映射成一個個的Java對象。類名.class:該方法最為安全可靠,程序性能更高。這說明任何一個類都有一個隱含的靜態成員變量 class。這種方法只適合在編譯前就知道操作的 Class,多用於傳遞參數。Class.forName(「類的全路徑名」) :當知道某類的全路徑名時,可以使用此方法獲取 Class 類對象。
  • 面試官:Java 反射是什麼?我回答不上來!
    一.概念反射就是把Java的各種成分映射成相應的Java類。Class類的構造方法是private,由JVM創建。反射是java語言的一個特性,它允程序在運行時(注意不是編譯的時候)來進行自我檢查並且對內部的成員進行操作。
  • 學Java不得不看的經典書籍
    因此本文為大家推薦Java學習的書籍,學雖容易,學好不易,且學且珍惜。【內容介紹】本書從初學者角度出發,通過通俗易懂的語言、豐富多彩的實例,詳細介紹了使用Java語言進行程序開發應該掌握的各方面技術。共覆蓋了java.awt、java.lang、java.io和java.nio、java.sql、java.text、java.util、javax.swing包下絕大部分類和接口。【推薦理由】本書並不單純從知識角度來講解Java,而是從解決問題的角度來介紹Java語言,所以本書中介紹了大量實用案例開發。
  • 反射——Java高級開發必須懂得
    描述:在 main 函數中,有一個 String args[] 參數,這就表示在執行某 .class 文件時,可以對 main 函數傳字符串參數(例如:命令行中:java OfficeBetter Excel,傳給主函數的參數就是Excel,如果傳多個參數,參數用空格隔開),Office類中使用了兩個類(沒有提供這兩個類),並調用其相應的方法
  • 「零基礎學JAVA」基礎篇 第二章 JAVA編程初體驗
    JAVA【零基礎學編程】系列今天給大家帶來基礎篇 第二章 JAVA編程初體驗本節的部分編碼操作需要先安裝JDK開發工具「零基礎學JAVA」工具篇 JDK的安裝教程(WINDOWS版)和環境變量的配置「零基礎學JAVA」工具篇