溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

Dagger2源碼分析(二):Java無(wú)所不能的反射在Android中需要熟練的知識(shí)

發(fā)布時(shí)間:2020-07-23 23:55:08 來(lái)源:網(wǎng)絡(luò) 閱讀:410 作者:Android飛魚(yú) 欄目:移動(dòng)開(kāi)發(fā)

前言

提起hook概念,相信大家都聽(tīng)說(shuō)過(guò),然后hook就是將反射和動(dòng)態(tài)代理運(yùn)用于Android平臺(tái)源碼之上的??墒?,反射的應(yīng)用場(chǎng)景缺非常廣泛,注解的內(nèi)容也同樣需要使用反射去獲取,所以反射是我們Android開(kāi)發(fā)者必須要學(xué)習(xí)的知識(shí)。

反射

什么是反射?

反射 (Reflection) 是 Java 的特征之一,它允許運(yùn)行中的 Java 程序獲取自身的信息,并且可以操作類或?qū)ο蟮膬?nèi)部屬性
簡(jiǎn)而言之,通過(guò)反射,我們可以在運(yùn)行時(shí)獲得程序或程序集中每一個(gè)類型的成員和成員的信息。程序中一般的對(duì)象的類型都是在編譯期就確定下來(lái)的,而 Java 反射機(jī)制可以動(dòng)態(tài)地創(chuàng)建對(duì)象并調(diào)用其屬性,這樣的對(duì)象的類型在編譯期是未知的。所以我們可以通過(guò)反射機(jī)制直接創(chuàng)建對(duì)象,即使這個(gè)對(duì)象的類型在編譯期是未知的。
反射的核心是 JVM 在運(yùn)行時(shí)才動(dòng)態(tài)加載類或調(diào)用方法/訪問(wèn)屬性,它不需要事先(寫(xiě)代碼的時(shí)候或編譯期)知道運(yùn)行對(duì)象是誰(shuí)。
Java 反射主要提供以下功能:

  • 在運(yùn)行時(shí)判斷任意一個(gè)對(duì)象所屬的類;

  • 在運(yùn)行時(shí)構(gòu)造任意一個(gè)類的對(duì)象;

  • 在運(yùn)行時(shí)判斷任意一個(gè)類所具有的成員變量和方法(通過(guò)反射甚至可以調(diào)用private方法);

  • 在運(yùn)行時(shí)調(diào)用任意一個(gè)對(duì)象的方法
    重點(diǎn):是運(yùn)行時(shí)而不是編譯時(shí)

反射的運(yùn)用
獲得 Class 對(duì)象

使用 Class 類的 forName 靜態(tài)方法

public?static?Class<?>?forName(String?className)

直接獲取某一個(gè)對(duì)象的 class

Class<?>?klass?=?int.class;Class<?>?classInt?=?Integer.TYPE;

調(diào)用某個(gè)對(duì)象的 getClass() 方法

StringBuilder?str?=?new?StringBuilder("123");
Class<?>?klass?=?str.getClass();
判斷是否為某個(gè)類的實(shí)例

一般地,我們用 instanceof 關(guān)鍵字來(lái)判斷是否為某個(gè)類的實(shí)例。同時(shí)我們也可以借助反射中 Class 對(duì)象的 isInstance() 方法來(lái)判斷是否為某個(gè)類的實(shí)例,它是一個(gè) native 方法:

public?native?boolean?isInstance(Object?obj);
創(chuàng)建實(shí)例

通過(guò)反射來(lái)生成對(duì)象主要有兩種方式。

  • 使用Class對(duì)象的newInstance()方法來(lái)創(chuàng)建Class對(duì)象對(duì)應(yīng)類的實(shí)例。

Class<?>?c?=?String.class;Object?str?=?c.newInstance();
  • 先通過(guò)Class對(duì)象獲取指定的Constructor對(duì)象,再調(diào)用Constructor對(duì)象的newInstance()方法來(lái)創(chuàng)建實(shí)例。這種方法可以用指定的構(gòu)造器構(gòu)造類的實(shí)例。

//獲取String所對(duì)應(yīng)的Class對(duì)象Class<?>?c?=?String.class;//獲取String類帶一個(gè)String參數(shù)的構(gòu)造器Constructor?constructor?=?c.getConstructor(String.class);
//根據(jù)構(gòu)造器創(chuàng)建實(shí)例
Object?obj?=?constructor.newInstance("23333");
System.out.println(obj);
獲取構(gòu)造器信息

得到構(gòu)造器的方法

Constructor?getConstructor(Class[]?params)?--?獲得使用特殊的參數(shù)類型的公共構(gòu)造函數(shù),?
Constructor[]?getConstructors()?--?獲得類的所有公共構(gòu)造函數(shù)?
Constructor?getDeclaredConstructor(Class[]?params)?--?獲得使用特定參數(shù)類型的構(gòu)造函數(shù)(與接入級(jí)別無(wú)關(guān))?
Constructor[]?getDeclaredConstructors()?--?獲得類的所有構(gòu)造函數(shù)(與接入級(jí)別無(wú)關(guān))

獲取類構(gòu)造器的用法與上述獲取方法的用法類似。主要是通過(guò)Class類的getConstructor方法得到Constructor類的一個(gè)實(shí)例,而Constructor類有一個(gè)newInstance方法可以創(chuàng)建一個(gè)對(duì)象實(shí)例:

public?T?newInstance(Object?...?initargs)
獲取類的成員變量(字段)信息

獲得字段信息的方法

Field?getField(String?name)?--?獲得命名的公共字段?
Field[]?getFields()?--?獲得類的所有公共字段?
Field?getDeclaredField(String?name)?--?獲得類聲明的命名的字段?
Field[]?getDeclaredFields()?--?獲得類聲明的所有字段
調(diào)用方法

獲得方法信息的方法

--?使用特定的參數(shù)類型,獲得命名的公共方法Method?getMethod(String?name,?Class[]?params)--?獲得類的所有公共方法Method[]?getMethods()??
--?使用特寫(xiě)的參數(shù)類型,獲得類聲明的命名的方法?
Method?getDeclaredMethod(String?name,?Class[]?params)?
--?獲得類聲明的所有方法?
Method[]?getDeclaredMethods()

當(dāng)我們從類中獲取了一個(gè)方法后,我們就可以用 invoke() 方法來(lái)調(diào)用這個(gè)方法。invoke 方法的原型為:

public?Object?invoke(Object?obj,?Object...?args)
????????throws?IllegalAccessException,?IllegalArgumentException,
???????????InvocationTargetException
利用反射創(chuàng)建數(shù)組

數(shù)組在Java里是比較特殊的一種類型,它可以賦值給一個(gè)Object Reference
其中的Array類為java.lang.reflect.Array類。我們通過(guò)Array.newInstance()創(chuàng)建數(shù)組對(duì)象,它的原型是:

public?static?Object?newInstance(Class<?>?componentType,?int?length)
????????throws?NegativeArraySizeException?{????????return?newArray(componentType,?length);
????}

而 newArray 方法是一個(gè) native 方法,它在 HotSpot JVM 里的具體實(shí)現(xiàn)我們后邊再研究,這里先把源碼貼出來(lái):

private?static?native?Object?newArray(Class<?>?componentType,?int?length)
????????throws?NegativeArraySizeException;
注意事項(xiàng)

反射會(huì)額外消耗一定的系統(tǒng)資源,因此如果不需要?jiǎng)討B(tài)地創(chuàng)建一個(gè)對(duì)象,那么就不需要用反射
反射調(diào)用方法時(shí)可以忽略權(quán)限檢查,因此可能會(huì)破壞封裝性而導(dǎo)致安全問(wèn)題


Java與Android內(nèi)核原理專題技術(shù)大綱;

Dagger2源碼分析(二):Java無(wú)所不能的反射在Android中需要熟練的知識(shí)


BAT主流Android架構(gòu)技術(shù)大綱+學(xué)習(xí)路線+全套視頻;

架構(gòu)技術(shù)詳解和學(xué)習(xí)路線與資料分享請(qǐng)看這篇;《BATJ一線大廠最主流的Android高級(jí)架構(gòu)技術(shù);體系詳解+學(xué)習(xí)路線》

(包括自定義控件、NDK、架構(gòu)設(shè)計(jì)、混合式開(kāi)發(fā)工程師(React native,Weex)、性能優(yōu)化、完整商業(yè)項(xiàng)目開(kāi)發(fā)等)


  • 阿里P8級(jí)Android架構(gòu)師技術(shù)腦圖;

Dagger2源碼分析(二):Java無(wú)所不能的反射在Android中需要熟練的知識(shí)


  • 全套體系化高級(jí)架構(gòu)視頻;七大主流技術(shù)模塊,視頻+源碼+筆記

Dagger2源碼分析(二):Java無(wú)所不能的反射在Android中需要熟練的知識(shí)


向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI