教學視頻:https://edu.51cto.com/course/5667.html?source=so
反射reflect
首先介紹 Java 中 Class 類與 Java 反射的基本用法,然後介紹具體的反射應用。爲了便於讀者理解,在講解過程中還結合了大量案例
一、認識反射機制
什麼是反射,比如這個人喫番薯會放屁,正常情況我們關心他喫喝放的過程,反射機制就是屁怎麼放出來的。
概念:反射機制是將泛型固定的類所有方法和成員全部顯示出來,以供程序員可以確定程序編寫是否有錯誤的機制;
通過反射去實現另外的功能。
有反也有正,我們看看請示正常的例子:
輸出就是日期:
所謂反就是通過對象找來源,在程序中,對象要想找到它的來源,就依靠Object類提供的方法:
範例:觀察反的操作
輸出就是該對象的Date的類名稱->ava.util.Date:
現象發現通過getClas()取得的Class對象,就可以直接找到對象的來源。這就是反射,反射反射就是從Class開始。
注意:反射中的泛型都用一個標記,就是問號:<?>,如:class<?>
二、實例化Class類對象
輸出:
爲什麼會出現class?這是因爲默認調用toString方法,我們改寫下(不要小看這兩種方法,我們要靠simpleName活呢):
輸出:
在實際開發中用getClass實際用的比較少;
死都要記住這種方法,好處就是可以直接使用字符串實例化對象,實例:
死都要記住這種方法:Class.ForName(“字符串”)
三、通過反射實例化對象(核心)
如果要產生實例化對象,就必現有new對象,有了反射後一切都變了。
在class類中提供了一個方法(一推異常拋出,這些異常不要記,可以查的,也不好記):
範例:正常實例化對象
輸出:
範例:反射實例化對象(對比上面)
輸出,結果都是一樣:
這個例子對比不出來?那在看一個自定義的例子
範例:通過反射實例化對象
輸出,也是調用了無參構造:
若是有參的情況呢?
這樣就是出現實例化異常。所以爲什麼在類中寫無參構造方法,1是給子類調用方便,2是給反射調用方便
寫到這裏大家會發現,用反射的方法比普通的方法多兩行,是不是有病?我們會學習工廠設計模式+反射機制
四、工廠設計模式修正(理解即可)
熟悉的三大設計模式:1.工廠設計模式;2.單例設計模式;3.代理設計模式;
工廠設計模式的本質在於想要取得接口的實例化對象不要直接使用關鍵字new,而應該通過工廠取得,只要自己寫的接口要想實現實例化對象要寫工廠99%;
範例:傳統工廠設計模式
輸出:
如果要增加子類,那意味着工廠也要跟着修改。
比如我們新增一個子類,如下:
這樣是能實現,如果增加很多很多子類,源源不斷的增加,你改都沒有它新增的快呢,怎麼解決?關鍵性就在new上,這是造成本次缺陷最大的元兇,可擴展性很差;這時候可以通過反射來實現工廠類,反射的特點:接收字符串。
注意:
等價於
這樣就不會頻繁加一個類就改工廠了。
以上的代碼只是分析出了關鍵字new實例化對象與構造方法實例化對象的區別,但是並不是意味着不適用關鍵字new了
反射適用於可擴充性,比new大,要寫過項目後,才反過來看才懂。
反射的三種方法:構造方法、普通方法、成員
五、反射調用的構造方法
這種取得本身是有問題的,因爲它本身只能調用無參構造,例如:
這個代碼一定報錯,沒有無參;
如果人不提供無參,那麼我們就不能用反射實例化了呢?錯!
如果類中沒有提供無參構造方法,那麼必須明確的調用知道的構造方法實現對象的實例化操作。這個方法是誰?
那麼必須要找到類中的構造方法定義:
這個是什麼意思?就是要找到參數的類型,比如上面代碼的例子,類型是String和int型,
所以我們代碼可以這麼寫:
找到了Constructor能幹什麼?
找到了java.lang.reflect.Constructor類之中在此類中提供一個實例化對象的方法,從此可以開始真正邁入反射了,
實例化對象:
範例:使用反射調用指定構造實例化對象
輸出:
對比使用反射和其他方法,那種方法省事、簡單。每個類的參數方法無法統一,反射可以。這就是爲什麼要有無參構造方法的主要原因。
六、反射調用的普通方法
類中的普通方法是在取得本類的實例化對象置纔可以進行調用的操作,所以即便使用了反射進行方法的調用,那麼也必現使用newInstance()取得實例化對象,在Class類中定義有如下取得方法對象的操作:取得方法:
範例:給了你類名稱(name),給了操作屬性(set、get方法),把value=“張三”,普通方法先實例化對象,
因爲getMethod的name首字母要大寫,哪個方法可以實現大寫,如下方法,自己擴充以下(注意行號):
返回值就是方法的返回值,,set有參數,get無參數,看上面
分析:
set沒有返回值,所以是get有,所以輸出是get
輸出:
以後代碼中給了屬性名稱,類的完整名稱,而後可以進行自動賦值操作,那麼基本上就是反射在起作用。set幾乎不會被調用,get方法纔會被調用。
七、反射調用的成員
構造方法調完了,普通方法掉完了,就剩下調用成員,這是三大組成部分,需要考慮兩種因素(Class類定義的方法),
一種是繼承而來,從父類來
二是本類定義的成員
在java中使用java.lang.reflect.Field類描述成員,有兩個方法:
1.取得成員內容(相當於對象.屬性):
2.設置成員內容:
範例:直接進行屬性調用
輸出報錯,私有屬性能訪問嗎?:
其實它是可以訪問的,幾乎所有的屬性都需要private封裝,要想解決封裝的困擾,可以利用File父類的方法完成
():
取消封裝:
設爲true就是取消封裝;
這樣取消封裝後才能運行:“
這就是反射。