什么是Java的反射機制?
java的反射機制是在運行狀態(tài)中,對于任意一個類(Class)都能知道他的屬性(Field)和方法(Method),對于任意一個對象都能夠調(diào)用它的方法和屬性;這種動態(tài)獲取信息以及動態(tài)調(diào)用對象方法的功能稱為java語言的反射機制。它允許正在運行的java程序觀測甚至是修改程序的動態(tài)行為。
反射的實現(xiàn)方式有哪些?
1、通過Class.forName()方法加載字符串
Class<?> clazz = Class.forName("java.lang.String")
2、通過類名調(diào)用class屬性得到該類的Class對象
Class<?> clazz = String.class
3、調(diào)用實例的getClass()方法
Class<?> clazz = date.getClass()
4、如果是基本類型的包裝類,則可以通過調(diào)用包裝類的Type屬性來獲得該包裝類的Class對象
反射調(diào)用是怎么實現(xiàn)的?
查閱 Method.invoke 的源代碼發(fā)現(xiàn),它實際上委派給 MethodAccessor 來處理。
public final class Method extends Executable {
...
public Object invoke(Object obj, Object... args) throws ... {
... // 權限檢查
MethodAccessor ma = methodAccessor;
if (ma == null) {
ma = acquireMethodAccessor();
}
return ma.invoke(obj, args);
}
}
MethodAccessor 是一個接口,它有兩個實現(xiàn):一個通過本地方法來實現(xiàn)反射調(diào)用,另一個使用了委派模式(委派實現(xiàn))。
在默認情況下,方法的反射調(diào)用為委派實現(xiàn),委派給本地實現(xiàn)來進行方法調(diào)用。在調(diào)用超過 15 次之后,委派實現(xiàn)便會將委派對象切換至動態(tài)實現(xiàn)。這個動態(tài)實現(xiàn)的字節(jié)碼是自動生成的,它將直接使用 invoke 指令來調(diào)用目標方法。
反射調(diào)用帶來哪些性能開銷?
1、接口的通用性,java的invoke方法是傳object和object[]數(shù)組的?;緟?shù)類型需要裝箱和拆箱,產(chǎn)生大量額外的對象和內(nèi)存開銷,頻繁促發(fā)GC。
2、編譯器難以對動態(tài)調(diào)用的代碼提前做優(yōu)化比如方法內(nèi)聯(lián)。
3、反射需要按名檢索類和方法,有一定的時間開銷。
反射在java中的應用有哪些?
1、java集成開發(fā)環(huán)境,每當我們敲入點號時,IDE便會根據(jù)點號前的內(nèi)容,動態(tài)展示可以訪問的字段和方法。
2、java調(diào)試器,它能夠在調(diào)試過程中枚舉某一對象所有字段的值。
3、web開發(fā)中,我們經(jīng)常接觸到各種配置的通用框架。為保證框架的可擴展性,他往往借助java的反射機制。例如Spring框架的依賴反轉(zhuǎn)(IOC)便是依賴于反射機制。
4、AOP攔截獲取方法信息。典型的例子:Spring緩存@Cacheable的key生成策略