在上篇 Java 反射機制(一) 介紹了一些 Java
反射相關的經常使用 API ,在知道了如何去使用反射以後,做爲一個合格的工程師,下一步確定是要去了解它的如何實現的,咱們今天就來看看在 JDK
源碼中是如何去實現反射的(PS:如下源碼分析基於 JDK1.8
)。html
Field
類的 set
方法是在運行時用來動態修改一個類的屬性的值,進入到 Field
類的 set
方法的源碼以下:java
public void set(Object obj, Object value) throws IllegalArgumentException, IllegalAccessException {
if (!override) {
if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
Class<?> caller = Reflection.getCallerClass();
checkAccess(caller, clazz, obj, modifiers);
}
}
getFieldAccessor(obj).set(obj, value);
}
複製代碼
首先根據 override
判斷是否須要檢查字段的訪問權限,而後經過 getFieldAccessor
方法得到一個 FieldAccessor
字段訪問者對象,最後調用的是 FieldAccessor
類的 set
方法進行下一步操做的,FieldAccessor
是一個接口,定義了對字段的一些操做,該接口有以下一些實現類:緩存
要看 set
到底調用的是哪一個實現類的方法,那麼咱們須要看看 getFieldAccessor()
返回的是哪一個類的對象,下面是 getFieldAccessor
方法的源碼實現:安全
// security check is done before calling this method
private FieldAccessor getFieldAccessor(Object obj) throws IllegalAccessException {
boolean ov = override;
FieldAccessor a = (ov) ? overrideFieldAccessor : fieldAccessor;
return (a != null) ? a : acquireFieldAccessor(ov);
}
複製代碼
這裏先經過 override
來獲取不一樣的緩存的 FieldAccessor
,其中 overrideFieldAccessor
表明本類覆蓋父類的字段訪問者對象緩存,fieldAccessor
是本類的字段訪問器對象緩存。若是緩存存在的話就直接複用以前的對象,不然就調用 Field
類的 acquireFieldAccessor
方法獲取。咱們進入到 acquireFieldAccessor
方法中看看,方法源碼以下:ide
private FieldAccessor acquireFieldAccessor(boolean overrideFinalCheck) {
// First check to see if one has been created yet, and take it
// if so
FieldAccessor tmp = null;
if (root != null) tmp = root.getFieldAccessor(overrideFinalCheck);
if (tmp != null) {
if (overrideFinalCheck)
overrideFieldAccessor = tmp;
else
fieldAccessor = tmp;
} else {
// Otherwise fabricate one and propagate it up to the root
tmp = reflectionFactory.newFieldAccessor(this, overrideFinalCheck);
setFieldAccessor(tmp, overrideFinalCheck);
}
return tmp;
}
複製代碼
從 acquireFieldAccessor
的源碼中咱們能夠看到,先判斷是否已存在 FieldAccessor
對象,若是存在的話那麼就會複用以前的 FieldAccessor
對象,不然就使用 reflectionFactory
工廠的 newFieldAccessor
方法生成一個新的 FieldAccessor
對象出來。因此咱們就要進到 newFieldAccessor
方法裏面看看是如何生成的,方法源碼以下:源碼分析
public FieldAccessor newFieldAccessor(Field var1, boolean var2) {
checkInitted();
return UnsafeFieldAccessorFactory.newFieldAccessor(var1, var2);
}
複製代碼
從 newFieldAccessor
方法代碼能夠得知,在方法裏面是經過 UnsafeFieldAccessorFactory
類的 static
方法 newFieldAccessor
來生產 FieldAccessor
的,那麼咱們繼續進入到 UnsafeFieldAccessorFactory
類的 newFieldAccessor
方法裏面看看,方法源碼以下:post
static FieldAccessor newFieldAccessor(Field var0, boolean var1) {
Class var2 = var0.getType();
boolean var3 = Modifier.isStatic(var0.getModifiers());
boolean var4 = Modifier.isFinal(var0.getModifiers());
boolean var5 = Modifier.isVolatile(var0.getModifiers());
boolean var6 = var4 || var5;
boolean var7 = var4 && (var3 || !var1);
if (var3) {
UnsafeFieldAccessorImpl.unsafe.ensureClassInitialized(var0.getDeclaringClass());
if (!var6) {
if (var2 == Boolean.TYPE) {
return new UnsafeStaticBooleanFieldAccessorImpl(var0);
} else if (var2 == Byte.TYPE) {
return new UnsafeStaticByteFieldAccessorImpl(var0);
} else if (var2 == Short.TYPE) {
return new UnsafeStaticShortFieldAccessorImpl(var0);
} else if (var2 == Character.TYPE) {
return new UnsafeStaticCharacterFieldAccessorImpl(var0);
} else if (var2 == Integer.TYPE) {
return new UnsafeStaticIntegerFieldAccessorImpl(var0);
} else if (var2 == Long.TYPE) {
return new UnsafeStaticLongFieldAccessorImpl(var0);
} else if (var2 == Float.TYPE) {
return new UnsafeStaticFloatFieldAccessorImpl(var0);
} else {
return (FieldAccessor)(var2 == Double.TYPE ? new UnsafeStaticDoubleFieldAccessorImpl(var0) : new UnsafeStaticObjectFieldAccessorImpl(var0));
}
}
// 剩下的部分省略...
}
}
複製代碼
從以上 UnsafeFieldAccessorFactory
類的 newFieldAccessor
方法代碼能夠看出,方法裏面經過類的字段修飾符類型和字段的類類型共同決定返回的 FieldAccessor
實現類,這裏要注意一下方法裏面這幾個變量的含義:性能
static
關鍵字修飾的屬性。final
關鍵字修飾的屬性。valatile
關鍵字修飾的屬性。valatile
關鍵字或者 final
關鍵字修飾的屬性。final
關鍵字修飾的屬性或者 static
關鍵字修飾而且不能覆蓋(override = false
)的屬性舉一個例子,假設在一個類中的字段聲明爲 public static String name
,那麼返回的字段訪問器爲 UnsafeStaticCharacterFieldAccessorImpl
,咱們看看這個類的 set
方法是如何實現的,方法源碼以下:ui
public void set(Object var1, Object var2) throws IllegalArgumentException, IllegalAccessException {
if (this.isFinal) {
this.throwFinalFieldIllegalAccessException(var2);
}
if (var2 == null) {
this.throwSetIllegalArgumentException(var2);
}
if (var2 instanceof Character) {
unsafe.putChar(this.base, this.fieldOffset, (Character)var2);
} else {
this.throwSetIllegalArgumentException(var2);
}
}
複製代碼
從上面方法的代碼得知,方法最終仍是經過 Unsafe
類的 native
方法 putChar(Object var1, long var2, char var4)
來實現的,有關 Unsafe
類的介紹請看這篇文章(Java魔法類:Unsafe應用解析)。this
Method
類的 invoke
方法用來在運行時動態調用對象的方法,咱們進入到 Method
類的 invoke
方法中看看在 JDK
中究竟是怎麼作的,方法源碼以下:
public Object invoke(Object obj, Object... args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
if (!override) {
if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
Class<?> caller = Reflection.getCallerClass();
checkAccess(caller, clazz, obj, modifiers);
}
}
MethodAccessor ma = methodAccessor; // read volatile
if (ma == null) {
ma = acquireMethodAccessor();
}
return ma.invoke(obj, args);
}
複製代碼
從以上方法代碼咱們能夠看到,和上文說的的 Field
類同樣,首先也是先根據 override
進行了一些權限檢查,最後調用的是 MethodAccessor
的 invoke
方法進行處理,這個方法訪問器 MethodAccessor
是一個接口,它只有一個操做方法調用的 invoke
方法,它有以下三個實現類:
要想知道 ma.invoke
具體調用的是哪一個類的方法,咱們須要看看方法 acquireMethodAccessor
返回的對象是哪一個,該方法的源碼以下:
private MethodAccessor acquireMethodAccessor() {
// First check to see if one has been created yet, and take it
// if so
MethodAccessor tmp = null;
if (root != null) tmp = root.getMethodAccessor();
if (tmp != null) {
methodAccessor = tmp;
} else {
// Otherwise fabricate one and propagate it up to the root
tmp = reflectionFactory.newMethodAccessor(this);
setMethodAccessor(tmp);
}
return tmp;
}
複製代碼
從以上方法 acquireMethodAccessor
的源碼能夠看出,首先會先先判斷是否已經存在了對應的 MethodAccessor
對象,若是有就會複用這個對象,不然就調用工廠 reflectionFactory
的 newMethodAccessor
方法生成一個 MethodAccessor
對象出來。那麼咱們就須要進入到方法 newMethodAccessor
中,方法源碼以下:
public MethodAccessor newMethodAccessor(Method var1) {
checkInitted();
if (noInflation && !ReflectUtil.isVMAnonymousClass(var1.getDeclaringClass())) {
return (new MethodAccessorGenerator()).generateMethod(var1.getDeclaringClass(), var1.getName(), var1.getParameterTypes(), var1.getReturnType(), var1.getExceptionTypes(), var1.getModifiers());
} else {
NativeMethodAccessorImpl var2 = new NativeMethodAccessorImpl(var1);
DelegatingMethodAccessorImpl var3 = new DelegatingMethodAccessorImpl(var2);
var2.setParent(var3);
return var3;
}
}
複製代碼
從方法 newMethodAccessor
的代碼能夠看到,方法首先是使用 Method
對象做爲入參生成了 NativeMethodAccessorImpl
對象,而後再使用 NativeMethodAccessorImpl
對象做爲入參生成了 DelegatingMethodAccessorImpl
對象。這個使用了代理模式
,將 NativeMethodAccessorImpl
交給了 DelegatingMethodAccessorImpl
類進行了代理,進入到代理類 DelegatingMethodAccessorImpl
中能夠看到:
從上面的紅色方框能夠看到,在類 DelegatingMethodAccessorImpl
的構造方法中將參數賦值給類中的 delegate
屬性,全部上所說的 ma.invoke
最終會進入到 DelegatingMethodAccessorImpl
代理類的 invoke
,方法裏調用的是 delegate
屬性的 invoke
方法,該屬性聲明的類型爲抽象類 MethodAccessorImpl
,它有以下兩個實現類:
按照上文所說的,這裏的 delegate
屬性是 NativeMethodAccessorImpl
對象,那麼就進入到 NativeMethodAccessorImpl
的 invoke
方法中,方法源碼以下:
public Object invoke(Object var1, Object[] var2) throws IllegalArgumentException, InvocationTargetException {
if (++this.numInvocations > ReflectionFactory.inflationThreshold() && !ReflectUtil.isVMAnonymousClass(this.method.getDeclaringClass())) {
MethodAccessorImpl var3 = (MethodAccessorImpl)(new MethodAccessorGenerator()).generateMethod(this.method.getDeclaringClass(), this.method.getName(), this.method.getParameterTypes(), this.method.getReturnType(), this.method.getExceptionTypes(), this.method.getModifiers());
this.parent.setDelegate(var3);
}
return invoke0(this.method, var1, var2);
}
複製代碼
類 NativeMethodAccessorImpl
的 invoke
方法會先判斷這次調用是否超過 ReflectionFactory.inflationThreshold()
方法返回的閾值(PS:默認的閾值大小爲 15
),若是超過了該閾值,則使用方法訪問生成器從新生成一個 MethodAccessorImpl
,並將 DelegatingMethodAccessorImpl
的 delegate
屬性指向這個新生成的 MethodAccessorImpl
對象。從 Reflectionfactory
工廠類的一下注釋:
能夠得知 JVM
初次加載字節碼實現反射的時候,使用 Method.invoke
和 Constructor.newInstance
方式加載所花費的時間是使用原生代碼加載所花費的時間的 3 - 4 倍。這也就是咱們日常說爲何頻繁使用反射的應用須要花費更多的時間。JVM
做者們爲了不這種花費較長的加載時間,咱們在第一次加載的時候重用了 JVM
的入口,以後切換到字節碼實現的實現。 正如註釋所述,在 MethodAccessor
接口的實現中,有兩個不一樣的版本,一個 Java
實現的,一個是 Native
實現的。Java
版本實現的版本在初始化的時須要比較多的時間,但長久來講性能會更好一些;而 Native
版本則正好相反,在初始化時相對較快,可是在運行一段時間以後性能就不如 Java
版本的了。爲了權衡兩種版本的特性,sun
公司的 JDK
使用了 inflation
機制,讓 Java
方法在被反射調用時,開頭的幾回調用使用 native
版,等反射調用次數超過閾值時則生成一個專用的 MethodAccessor
實現類,生成其中的 invoke
方法的字節碼,之後對該 Java
方法的反射調用就會使用 Java
版。
本文主要介紹反射調用 set(Object obj, Object value)
方法和 invoke(Object obj, Object... args)
方法的底層實現,因爲水平有限本人暫時尚未能力分析 JVM
的實現,這裏只分析到最終 native
方法的調用。底層會依賴到 Unsafe
類來執行一些低級別、不安全操做的方法,如直接訪問系統內存資源、自主管理內存資源等,這些方法在提高 Java
運行效率、加強 Java
語言底層資源操做能力方面起到了很大的做用。對於屬性反射的方法 setXXX
和 getXXX
的實現分別對應 Unsafe
類的 putXXX
和 getXXX
方法,也就是說徹底依賴 Unsafe
類中的 native
方法來實現的;對於方法反射的方法 invoke
底層調用的是 NativeMethodAccessorImpl
類的 invoke0
的 native
方法來實現的。對於反射構造器調用的實現,讀者能夠本身進入其源碼進行分析,大致上和反射方法調用的實現相似。
參考文章