JavaSE:第十三章:一分鐘了解反射

首先分享一篇關(guān)于反射的博文,因為我發(fā)現(xiàn)這篇博文寫的很詳細,地址是:https://blog.csdn.net/sinat_38259539/article/details/71799078

然后開始我的表演:



首先學習反射之前,我要提出疑問:
反射是個什么東西?它是用來做什么的?平時的應用場景有哪些?為啥要用它?它有什么優(yōu)缺點?它的工作原理是什么?我怎么使用它?

這么多的問題,這是在挑釁啊,既然如此,那么我想起來宮本的那句:想挑戰(zhàn)的,一個一個來

先解決第一個問題:
此為何物

百度看了看反射的介紹:



















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

我們來一句話定義反射:
反射就是把java類中的各種成分映射成一個個的Java對象

不理解這句話什么意思?沒關(guān)系,在我百度了幾分鐘后,找到三種解釋:

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

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

反射機制是不知道類是什么樣的,它是根據(jù)類的類名,去獲取一個實例,然后根據(jù)方法名去執(zhí)行方法。好比說,一般情況下畫一只老虎,問我得先知道老虎長什么樣子才能畫出來;有了反射機制,我只要知道“老虎”這答個名字就能畫出來。

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

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














現(xiàn)在我們基本已經(jīng)了解什么是反射了,接著需要將第二個問題搞定:
該物用途

然后接著百度:

 用途太多,概念也很多,我需要一句話就可以解釋它的作用或者用途:
反射可以賦予jvm動態(tài)編譯的能力

看到又出現(xiàn)一個詞,動態(tài)編譯,來我們來嘮嘮這個詞

Java中編譯類型有兩種:

 

    靜態(tài)編譯:一次性編譯。在編譯的時候把你所有的模塊都編譯進去。
    動態(tài)編譯:按需編譯。程序在運行的時候,用到那個模塊就編譯哪個模塊。

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

    靜態(tài)編譯:我想看個txt,點擊應用程序圖標以后,三個功能都加載進來了。在這里,另外兩個模塊的作用就是占用系統(tǒng)資源。
    動態(tài)編譯:我想看個txt,點擊應用程序,判斷格式,只加載讀txt模塊,使用讀txt模塊。

顯然,動態(tài)編譯1速度快,2節(jié)省了系統(tǒng)資源,3利于今后拓展。

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

    場景一:在日常的第三方應用開發(fā)過程中,經(jīng)常會遇到某個類的某個成員變量、方法或是屬性是私有的或是只對系統(tǒng)應用開放,這時候就可以利用Java的反射機制通過反射來獲取所需的私有成員或是方法。
    場景二:當我們在使用IDE(如Eclipse,IDEA)時,當我們輸入一個對象或類并想調(diào)用它的屬性或方法時,一按點號,編譯器就會自動列出它的屬性或方法,這里就會用到反射。
    場景三:反射最重要的用途就是開發(fā)各種通用框架。很多框架(比如Spring)都是配置化的(比如通過XML文件配置JavaBean,Action之類的),為了保證框架的通用性,它們可能需要根據(jù)配置文件加載不同的對象或類,調(diào)用不同的方法。

為啥要用它?它有什么優(yōu)缺點?

java的反射機制就是增加程序的靈活性,解耦。反射就是一種機制,可以讓你僅知道類的名字的情況下,可以了解整個類的內(nèi)部的結(jié)構(gòu),并且訪問內(nèi)部的成員和方法等。

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

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

優(yōu)勢:

    增加程序的靈活性,避免將固有的邏輯程序?qū)懰赖酱a里
    代碼簡潔,可讀性強,可提高代碼的復用率

缺點:

    相較直接調(diào)用在量大的情景下反射性能下降
    存在一些內(nèi)部暴露和安全隱患

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

    尋找類 Class 字節(jié)碼的過程
    安全管理機制的權(quán)限驗證等等
    若需要調(diào)用 native 方法調(diào)用時 JNI 接口的使用

反射的工作原理?反射技術(shù)的組成部分?

萬物皆對象,我們定義的類其實從面向?qū)ο蟮慕嵌葋矸治?,它其實也是一個具體的對象,它是一個描述類的實例。描述這個類中有哪些屬性,行為等等內(nèi)容.。我們可以通過定義類,來描述一組具有相同屬性,行為的實例對象。比如我們創(chuàng)建 Person 類

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

我們可以基于這個類創(chuàng)建具體不同身份證號和姓名的 Person 實例(new Person)。每一個實例都具有身份證號,年齡,說話的行為。通過上面的簡單案例,我們可以這么理解在Java 語言中 Class 的定義,是創(chuàng)建對象的統(tǒng)一模板.。那么我們可以思考這樣一個問題,既然不管是 Java 語言默認的類還是我們自定義創(chuàng)建的類都 是為了創(chuàng)建具有相同行為屬性的對象的模板。

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

那么既然每一個類都會具備這樣的內(nèi)容,那么這些類對象實例,應該也可以抽取成一個公有的模板,用于創(chuàng)建類對象實例的模板。所以在java 中,這個類定義的創(chuàng)建模板就是我們 java 語言中的 java.lang.Class 類。在 Class 的模板中,我們也可以找到大家耳熟能詳?shù)哪0孱惾鏜ethod,Constructor,F(xiàn)ield ...

深入 Class 內(nèi)部

通過上面的內(nèi)容,我們已經(jīng)了解到我們創(chuàng)建的每一個自定義的Class實例都是基于他的模板類java.lang.Class 類。在大家每一個編寫的類實例中,都會定義這個類的包名,類名,訪問域,特征符,構(gòu)造器,字段,函數(shù),父類,接口等等內(nèi)容。這些內(nèi)容在我們的 Class 類中都提供了對應的獲取方法進行獲取。

如何使用?

反射-基本信息操作

    int modifier = clazz.getModifiers(); //獲取類的修飾符
    Package package= clazz.getPackage();//獲取類的包名
    String fullClassName = clazz.getName();//獲取類的全路徑名稱
    String simpleClassName = clazz.getSimpleName();//獲取類的簡單名稱
    ClassLoader classLoader = clazz.getClassLoader();//獲取類的類加載器
    Class[] interfacesClasses = clazz.getInterfaces();//獲取類實現(xiàn)的接口列表
    Class fc= clazz.getSuperclass();//獲取類的父類
    Annotation[] annotations= clazz.getAnnotations(); //獲取類的注解列表

反射-字段操作

    Field[] fields = clazz.getFields();//獲取類中所有的公有字段 包含繼承
    Field[] declaredFields=clazz.getDeclaredFields();//獲取類中定義的字段 內(nèi)部
    Field nameField=clazz.getField("name");//獲取指定名稱的公有字段
    Field likeDescField=clazz.getDeclaredField("likeDesc");//獲取指定名稱類中定義的字段
    int modifersFiled = likeDescField.getModifiers();//獲取字段的修飾
    nameField.setAccessible(true);//指定字段強制訪問
    nameField.set(person,"小皮皮");//成員字段賦值(需指定對象)
    descriptionField.set(null,"沒有結(jié)婚的都是男孩!");//靜態(tài)字段賦值

反射-方法操作

    Method[] methods = clazz.getMethods();//獲取類中所有的公有方法 繼承
    Method[] declaredMethods = clazz.getDeclaredMethods();//獲取類中定義的方法
    Method talkMethod = clazz.getMethod("talk", String.class);//獲取類中指定名稱和參數(shù)的公有方法
    Method pugMethod = clazz.getDeclaredMethod("pickUpGirls") //獲取類中定義指定名稱和參數(shù)的方法
    int modifers = pugMethod .getModifiers();//獲取方法的修飾符
    talkMethod.invoke(boy,"I LOVE SEVEN");//指定對象進行成員方法的調(diào)用
    pugMethod .setAccessible(true);//指定方法的強制訪問
    pickUpGirlsMethod.invoke(null);//靜態(tài)方法的調(diào)用

反射-構(gòu)造器操作

    Constructor[] cons = clazz.getConstructors();//獲取類中所有的公有構(gòu)造器
    Constructor[] cons = clazz.getDeclaredConstructors();//獲取類中所有的構(gòu)造器
    Constructor conNoParam= clazz.getDeclaredConstructor();//獲取類中無參的構(gòu)造器
    Constructor con= clazz.getDeclaredConstructor(String.class,String.class); //獲取類中有參構(gòu)造
    int modifers = con.getModifiers();//獲取構(gòu)造器的修飾符
    conNoParam.newInstance();//構(gòu)造器實例對象
    con.setAccessible(true);//指定方法的強制訪問
    con.newInstance('abc','def');//有參構(gòu)造調(diào)用
    class.newInstacne();//class直接調(diào)用默認無參構(gòu)造


歡迎關(guān)注微信ID:SeniorRD