1、認識反射
“反”茬祷,有反就有“正”厂抖。正常情況先有類,再產(chǎn)生對象卧檐。所謂的反就是可以利用對象找到對象的出處:
在Object類里面提供有一個方法:取得Class對象:
public final Class getClass()墓懂;
可以輸出類的完整名稱,就找到了對象的出處霉囚。
Class類對象的實例化:
java.lang.Class是一個類捕仔。這個類是反射操作的源頭,所有的反射都要從此類開始進行。最關鍵的是這個類有三種實例化方式榜跌。
1闪唆、調(diào)用Object類中的getClass()方法:Class cls = mIntent.getClass();需要實例化對象钓葫,需要import導入類
2悄蕾、使用“類.class”取得:Class cls = Intent.class。不需要實例化對象础浮,需要import導入類
3帆调、調(diào)用Class類提供的方法:Class.forName(String className)。不需要import語句導入一個明確的類
反射實例化對象豆同。
當拿到一個類的時候番刊,肯定用關鍵字new進行對象的實例化操作,但是如果有了Class類對象后诱告,就可以不用New關鍵字也可以進行對象的實例化操作:
public T newInstance()相當于使用new調(diào)用無參構(gòu)造函數(shù)撵枢。
有了反射之后民晒,進行實例化的操作不再只是單單依靠關鍵字new完成了精居。反射也可以。
所以用反射獲取一個對象實例化的步驟為:
1潜必、先獲取Class類的實例化對象:Class cls = Class.forName(“xxxxxx”);
2靴姿、用Class類的實例化對象獲取制定類的實例化對象:Book book=(Book)cls.newInstance();
但是本來用關鍵字new一行代碼就可以完成實例化操作,反射需要兩步磁滚,這樣好嗎佛吓?
2、理解反射的作用
在任何開發(fā)中垂攘,一起的耦合都起源于new维雇。
看工程模式。如果想要擴展晒他,就必須改動工廠類中的if else吱型。如果一直擴展,就需要一直修改工廠類陨仅。因為工廠類中是通過New產(chǎn)生對象實例的津滞,所以New就是問題的關鍵。
如果工廠中用反射代替new灼伤,就不需要if else和new實例化每個if else中的對象触徐。只需要傳入類的完整名稱,就可以解耦和狐赡。擴展性非常的強撞鹉!
3、利用反射調(diào)用類的結(jié)構(gòu)
a、使用反射調(diào)用構(gòu)造:
之前所說的newInstance()方法實際上等于調(diào)用了無參構(gòu)造函數(shù)孔祸,但是實際中可能么有無參構(gòu)造函數(shù)隆敢,
Class中有方法可以取到構(gòu)造:public Constructor[]getConstructors():取得全部構(gòu)造。
和:public Constructor getConstructor(Class… paramterTypes):取得一個指定參數(shù)順序的構(gòu)造函數(shù)崔慧。
Constructor類是java.lang.reflect拂蝎,這時候真正到了反射中。
實例化對象方法public T newInstance(Object… initargs)
所以用反射獲取一個沒有無參構(gòu)造函數(shù)的類的實例化對象步驟為:
1惶室、先獲取Class類對象:Class cls = Class.forName(“xxxxx”);
2温自、獲取指定參數(shù)類型順序的構(gòu)造函數(shù):Constructor con = cls.getConstructor(Sring.class,double.class);
3、使用獲取到的構(gòu)造函數(shù)實例化對象:Object obj = con.newInstance(“第一個參數(shù)字符串類型”皇钞,10086.8)悼泌;
所以建議,不管有多少個構(gòu)造方法夹界,都盡量提供一個無參構(gòu)造函數(shù)馆里,不然太麻煩了。
b可柿、反射調(diào)用方法:
Class類中提供了一下方法用來獲取類的方法:
public Method[]getMethods()
public Method getMethod(String methodName,Class… paramterTypes)
Method類似java.lang.reflect包下的鸠踪,其中有個
public Object invoke(Object obj,Object… args)方法。
所以用反射調(diào)用方法的步驟為:
1复斥、先獲取Class對象:Class cls = Class.forName(“xxxxx”)营密;
并獲取對象Object object = cls.newInstance();//必須給出實例化對象
2、獲取指定方法:Method setTitleMethod = cls.getMethod(“setTitle”,String.class);
3目锭、調(diào)用方法:setTitleMethod.invoke(object,“一本書的標題”)评汰;//等價于Book對象.setTitle(“一本書的標題”)
但是這個過程中完全沒有出現(xiàn)過Book。也就是說痢虹,利用反射可以實現(xiàn)任意類的制定方法的調(diào)用被去。
c、反射調(diào)用成員:
類中的屬性一定要在本類實例化對象產(chǎn)生后才可以分配內(nèi)存空間奖唯。
Class類中提供了取得成員的方法:
1惨缆、取得全部成員:public Field[]getDeclaredFields()
2、取得指定成員:public Field getDeclaredField(String fieldName)
Field是java.lang.reflect包下臭埋。其中有:
1踪央、取得屬性內(nèi)容:public Object get(Object obj);
2、設置屬性內(nèi)容:public void set(Object obj,Object value)
所以反射調(diào)用成員的步驟為:
假設一個Book類瓢阴,里面只有一個屬性private String title;沒有getter/setter方法畅蹂。
1、先獲取Class對象:Class cls = Class.forName(“xxx”);
2荣恐、獲取對象:Object obj = cls.newInstance();
3液斜、獲取指定成員:Field titleField = cls.getDeclaredField(“title”);
4累贤、設置屬性內(nèi)容:titleField.set(obj,“書的名字”)少漆;//相當于:Book類對象.title =“書的名字“
但是調(diào)用get還是會報錯臼膏。因為封裝性。
這時候需要用到:AccessbleObject
在java.lang.reflect.AccessibleObject類下面(JDK1.8修改):
~ Executable//可執(zhí)行的
~ Constrictor
~Method
~Field
在這個類中有一個方法:
public void setAccessible(boolean flag)設置是否封裝示损,
設置為false后渗磅,就是取消封裝,這個時候再調(diào)用剛才的get就可以正常調(diào)用了检访。
構(gòu)造方法和普通方法一樣可以取消封裝始鱼,只不過很少這樣去做,而且對屬性的訪問還是應該是getter和setter方法完成脆贵。
學習完這些医清,反射算是入門了。