日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

反射底层原理

發(fā)布時間:2024/1/1 编程问答 22 豆豆
生活随笔 收集整理的這篇文章主要介紹了 反射底层原理 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

反射底層原理

反射作用

首先回顧一下反射的作用,反射可以根據(jù)一個類的Class對象獲得該類的Field、Constructor、Method對象,并對這三類對象進(jìn)行操作。

反射獲得Class對象的方法有三種:

  • 已知類名:Clazz.class
  • 已知全限定名:Class.forName(“xx.xx.Clazz”)
  • 已知對象:instance.getClass()

反射底層實現(xiàn)原理

反射的緩存

利用Class對象從JVM獲得的Field、Constructor、Method對象的存儲定義在Class類中的靜態(tài)內(nèi)部類ReflectionData<T>中;Class對象持有一個ReflectData<T>的軟引用實例:

private volatile transient SoftReference<ReflectionData<T>> reflectionData;private static class ReflectionData<T> {volatile Field[] declaredFields;volatile Field[] publicFields;volatile Method[] declaredMethods;volatile Method[] publicMethods;volatile Constructor<T>[] declaredConstructors;volatile Constructor<T>[] publicConstructors;// Intermediate results for getFields and getMethodsvolatile Field[] declaredPublicFields;volatile Method[] declaredPublicMethods;volatile Class<?>[] interfaces;// Value of classRedefinedCount when we created this ReflectionData instancefinal int redefinedCount;ReflectionData(int redefinedCount) {this.redefinedCount = redefinedCount;} }

由于這個屬性是軟引用的,在某些內(nèi)存比較苛刻的情況下是可能被回收的,也可以通過-XX:SoftRefLRUPolicyMSPerMB這個參數(shù)來控制回收的時機(jī)。

反射獲取的方式

以獲取類的Method為例:

  • 獲取所有方法

獲取所有方法會調(diào)用getDeclaredMethods方法:

@CallerSensitive public Method[] getDeclaredMethods() throws SecurityException {checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true);return copyMethods(privateGetDeclaredMethods(false)); }

該方法會先檢查是否允許訪問,默認(rèn)策略是允許的,然后會調(diào)用privateGetDeclaredMethods(boolean publicOnly)去進(jìn)行尋找該類的方法,傳入的boolean參數(shù)決定是否只獲取定義為public的方法:

private Method[] privateGetDeclaredMethods(boolean publicOnly) {checkInitted();Method[] res;ReflectionData<T> rd = reflectionData();if (rd != null) {res = publicOnly ? rd.declaredPublicMethods : rd.declaredMethods;if (res != null) return res;}// No cached value available; request value from VMres = Reflection.filterMethods(this, getDeclaredMethods0(publicOnly));if (rd != null) {if (publicOnly) {rd.declaredPublicMethods = res;} else {rd.declaredMethods = res;}}return res; }

該方法中可以看到會首先檢查reflectionData中是否已經(jīng)緩存了結(jié)果;

如果緩存中沒有,再通過getDeclaredMethods0()從虛擬機(jī)去獲取,該方法是一個native方法。

最后根據(jù)privateGetDeclaredMethods方法返回的Method數(shù)組,調(diào)用copyMethods()復(fù)制一份相同的Method數(shù)組進(jìn)行返回:

private static Method[] copyMethods(Method[] arg) {Method[] out = new Method[arg.length];ReflectionFactory fact = getReflectionFactory();for (int i = 0; i < arg.length; i++) {out[i] = fact.copyMethod(arg[i]);}return out; }
  • 獲取某個方法

獲取某個方法會調(diào)用searchMethods方法從上面提到的privateGetDeclaredMethods返回的Method數(shù)組里找到一個同名的匹配的方法:

@CallerSensitive public Method getDeclaredMethod(String name, Class<?>... parameterTypes)throws NoSuchMethodException, SecurityException {checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true);Method method = searchMethods(privateGetDeclaredMethods(false), name, parameterTypes);if (method == null) {throw new NoSuchMethodException(getName() + "." + name + argumentTypesToString(parameterTypes));}return method; }

searchMethods方法并不會直接返回匹配的Method對象,而是利用反射工廠(ReflectionFactory)去復(fù)制一個新的Method對象

private static Method searchMethods(Method[] methods, String name, Class<?>[] parameterTypes) {Method res = null;String internedName = name.intern();for (int i = 0; i < methods.length; i++) {Method m = methods[i];if (m.getName() == internedName&& arrayContentsEq(parameterTypes, m.getParameterTypes())&& (res == null|| res.getReturnType().isAssignableFrom(m.getReturnType())))res = m;}return (res == null ? res : getReflectionFactory().copyMethod(res)); }

反射工廠的copyMethod()方法的具體實現(xiàn)是Method類中的copy()方法:

Method copy() {if (this.root != null)throw new IllegalArgumentException("Can not copy a non-root Method");Method res = new Method(clazz, name, parameterTypes, returnType,exceptionTypes, modifiers, slot, signature,annotations, parameterAnnotations, annotationDefault);res.root = this;// Might as well eagerly propagate this if already presentres.methodAccessor = methodAccessor;return res; }

由此可見,我們每次通過調(diào)用getDeclaredMethod方法返回的Method對象其實都是一個新的對象。

利用反射進(jìn)行方法的調(diào)用

獲得了Method對象之后,就可以通過Method.invoke()方法調(diào)用該方法:

@CallerSensitive 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 volatileif (ma == null) {ma = acquireMethodAccessor();}return ma.invoke(obj, args); }

從上述代碼可以看到,方法的實際調(diào)用(invoke)實際是通過MethodAccessor進(jìn)行的;MethodAccessor接口定義了invoke方法:

public interface MethodAccessor {Object invoke(Object var1, Object[] var2) throws IllegalArgumentException, InvocationTargetException; }

MethodAccessor有三個實現(xiàn):

  • NativeMethodAccessorImpl:使用native方法去調(diào)用方法;

  • MethodAccessorImpl:抽象類,并沒有提供invoke方法的具體實現(xiàn);

  • DelegatingMethodAccessorImpl:繼承了MethodAccessorImpl,是一個代理,可以通過構(gòu)造函數(shù)或setter方法設(shè)置具體的實現(xiàn);其invoke方法的實現(xiàn)是調(diào)用其代理實現(xiàn)的invoke:

    class DelegatingMethodAccessorImpl extends MethodAccessorImpl {private MethodAccessorImpl delegate;DelegatingMethodAccessorImpl(MethodAccessorImpl var1) {this.setDelegate(var1);}public Object invoke(Object var1, Object[] var2) throws IllegalArgumentException, InvocationTargetException {return this.delegate.invoke(var1, var2);}void setDelegate(MethodAccessorImpl var1) {this.delegate = var1;} }

那么為什么要設(shè)計DelegatingMethodAccessorImpl這樣一個代理呢?

繼續(xù)往下看,會根據(jù)方法的調(diào)用次數(shù)切換MethodAccessor的具體實現(xiàn),利用DelegatingMethodAccessorImpl這樣一個代理的setter方法,就可以輕松切換。

至于為什么要切換,也留到后面再說。

那么具體是使用哪個MethodAccessor來實現(xiàn)方法的調(diào)用的呢?

回到上面的Method.invoke()方法中,會調(diào)用acquireMethodAccessor方法去獲取MethodAccessor,我們來詳細(xì)分析獲取的過程:

private MethodAccessor acquireMethodAccessor() {// First check to see if one has been created yet, and take it// if soMethodAccessor tmp = null;if (root != null) tmp = root.getMethodAccessor();if (tmp != null) {methodAccessor = tmp;} else {// Otherwise fabricate one and propagate it up to the roottmp = reflectionFactory.newMethodAccessor(this);setMethodAccessor(tmp);}return tmp; }

這個方法很簡單,首先查詢緩存(Method類的一個字段);如果沒有獲取過,就調(diào)用反射工廠的newMethodAccessor方法去創(chuàng)建一個,并存到對象對應(yīng)的字段中去;

我們來看newMethodAccessor方法:

public MethodAccessor newMethodAccessor(Method var1) {checkInitted();if (noInflation && !ReflectUtil.isVMAnonymousClass(var1.getDeclaringClass())) {// 利用字節(jié)碼生成一個MethodAccessorreturn (new MethodAccessorGenerator()).generateMethod(var1.getDeclaringClass(), var1.getName(), var1.getParameterTypes(), var1.getReturnType(), var1.getExceptionTypes(), var1.getModifiers());} else {// 使用NativeMethodAccessorNativeMethodAccessorImpl var2 = new NativeMethodAccessorImpl(var1);DelegatingMethodAccessorImpl var3 = new DelegatingMethodAccessorImpl(var2);var2.setParent(var3);return var3;} }

checkInitted方法我們留到后面再講,首先看生成的MethodAccessor,會有兩種可能:

  • 如果noInflation參數(shù)為true(默認(rèn)為false,后面再介紹具體含義),另一個參數(shù)不去管它:會由MethodAccessorGenerator根據(jù)字節(jié)碼相當(dāng)于生成一個虛擬的Class對象來調(diào)用其相應(yīng)的方法;(這種方法性能會好很多,相當(dāng)于直接調(diào)用一個類的某個方法
  • 否則,MethodAccessor實際是一個代理NativeMethodAccessor的DelegatingMethodAccessor(實際調(diào)用native方法的invoke)。

根據(jù)上面的分析,可以得知實際的MethodAccessor實現(xiàn)有兩個版本,一個是Java實現(xiàn)的,另一個是native實現(xiàn)的。它們兩個的性能各有優(yōu)劣:Java實現(xiàn)的版本會在初始化時需要較多時間,但長久來說性能較好;native版本正好相反,啟動時相對較快,但運(yùn)行時間長了之后速度就比不過Java版了。

那么如何權(quán)衡兩種實現(xiàn)呢?根據(jù)邏輯我們也可以輕松想到,就是通過一個參數(shù)來統(tǒng)計使用次數(shù):如果偶爾使用,我們就使用native版本;如果經(jīng)常使用,就用jdk版本。

jdk中關(guān)于這個參數(shù)有兩個設(shè)置,上面newMethodAccessor方法中我們還沒具體介紹的checkInitted方法就是去檢查這個參數(shù)的,該參數(shù)有兩種設(shè)置:

  • -Dsun.reflect.inflationThreshold=xxx:默認(rèn)15,表示超過15次使用JDK版本的MethodAccessor。
  • -Dsun.reflect.noInflation=true:直接不使用native版本的;我們從newMethodAccessor方法中也可以看到如果noInflation為true就直接創(chuàng)建JDK版本的。

根據(jù)默認(rèn)的noInflation為false,會在15次調(diào)用之前使用NatvieMethodAccessor,在該類中會對調(diào)用次數(shù)進(jìn)行統(tǒng)計,當(dāng)超過15次時,就會調(diào)用代理(DelegatingMethodAccerssorImpl)的setter方法切換成JDK版本的,這也就是之前提到的這個代理的作用,具體請看下面代碼:

class NativeMethodAccessorImpl extends MethodAccessorImpl {private final Method method;private DelegatingMethodAccessorImpl parent;private int numInvocations;NativeMethodAccessorImpl(Method var1) {this.method = var1;}public Object invoke(Object var1, Object[] var2) throws IllegalArgumentException, InvocationTargetException {// 每次調(diào)用invoke之前先計數(shù)if (++this.numInvocations > ReflectionFactory.inflationThreshold() && !ReflectUtil.isVMAnonymousClass(this.method.getDeclaringClass())) {// 如果超過了inflationThreshold設(shè)置的值,就會切換成JDK版本的MethodAccessor實現(xiàn)MethodAccessorImpl var3 = (MethodAccessorImpl)(new MethodAccessorGenerator()).generateMethod(this.method.getDeclaringClass(), this.method.getName(), this.method.getParameterTypes(), this.method.getReturnType(), this.method.getExceptionTypes(), this.method.getModifiers());// 利用代理的setter方法實現(xiàn)切換this.parent.setDelegate(var3);}// 使用native版本的invokereturn invoke0(this.method, var1, var2);}void setParent(DelegatingMethodAccessorImpl var1) {this.parent = var1;}private static native Object invoke0(Method var0, Object var1, Object[] var2); }

總結(jié)

以上是生活随笔為你收集整理的反射底层原理的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。