java反射機(jī)制

前言:

反射在我的日常開發(fā)中,實(shí)際使用的其實(shí)并不多,但是又和開發(fā)息息相關(guān),動(dòng)態(tài)代理、spring的ioc、aop、聲明式編程等等,底層都用到了反射, 我們不直接使用反射,但間接的處處在使用反射, 所以這里記錄一下反射源碼學(xué)習(xí)的心得。如又錯(cuò)誤,請(qǐng)留言區(qū)不吝指正。

反射api

(這里直接從網(wǎng)上copy了一份)

通常來說,使用反射 API 的第一步便是獲取 Class 對(duì)象。在 Java 中常見的有這么三種。

  1. 使用靜態(tài)方法 Class.forName 來獲取。
  2. 調(diào)用對(duì)象的 getClass() 方法。
  3. 直接用類名 +“.class”訪問。對(duì)于基本類型來說,它們的包裝類型(wrapper classes)擁有一個(gè)名為“TYPE”的 final 靜態(tài)字段,指向該基本類型對(duì)應(yīng)的 Class 對(duì)象。

例如,Integer.TYPE 指向 int.class。對(duì)于數(shù)組類型來說,可以使用類名 +“[ ].class”來訪問,如 int[ ].class。

除此之外,Class 類和 java.lang.reflect 包中還提供了許多返回 Class 對(duì)象的方法。例如,對(duì)于數(shù)組類的 Class 對(duì)象,調(diào)用 Class.getComponentType() 方法可以獲得數(shù)組元素的類型。

一旦得到了 Class 對(duì)象,我們便可以正式地使用反射功能了。下面我列舉了較為常用的幾項(xiàng)。

  1. 使用 newInstance() 來生成一個(gè)該類的實(shí)例。它要求該類中擁有一個(gè)無參數(shù)的構(gòu)造器。
  2. 使用 isInstance(Object) 來判斷一個(gè)對(duì)象是否該類的實(shí)例,語法上等同于 instanceof 關(guān)鍵字(JIT 優(yōu)化時(shí)會(huì)有差別,我會(huì)在本專欄的第二部分詳細(xì)介紹)。
  3. 使用 Array.newInstance(Class,int) 來構(gòu)造該類型的數(shù)組。
  4. 使用 getFields()/getConstructors()/getMethods() 來訪問該類的成員。除了這三個(gè)之外,Class 類還提供了許多其他方法,詳見 [4]。需要注意的是,方法名中帶 Declared 的不會(huì)返回父類的成員,但是會(huì)返回私有成員;而不帶 Declared 的則相反。

當(dāng)獲得了類成員之后,我們可以進(jìn)一步做如下操作。

  • 使用 Constructor/Field/Method.setAccessible(true) 來繞開 Java 語言的訪問限制。
  • 使用 Constructor.newInstance(Object[]) 來生成該類的實(shí)例。
  • 使用 Field.get/set(Object) 來訪問字段的值。
  • 使用 Method.invoke(Object, Object[]) 來調(diào)用方法。

源碼

反射可以分為本地實(shí)現(xiàn)(NativeMethodAccessorImpl),動(dòng)態(tài)實(shí)現(xiàn)(MethodAccessorGenerator)和委派實(shí)現(xiàn)(DelegatingMethodAccessorImpl)。這里委派實(shí)現(xiàn)并不是一種真實(shí)的實(shí)現(xiàn)方式,他是一個(gè)代理,任何反射調(diào)用總是先調(diào)用DelegatingMethodAccessorImpl,如果需要調(diào)用本地實(shí)現(xiàn),就由DelegatingMethodAccessorImpl調(diào)用本地實(shí)現(xiàn),如果需要調(diào)用動(dòng)態(tài)實(shí)現(xiàn),就由DelegatingMethodAccessorImpl調(diào)用動(dòng)態(tài)實(shí)現(xiàn)。下面看一下源碼

Method.invoke()

簡單來說,invoke最終交給MethodAccessor來實(shí)現(xiàn)

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);
        }
    }
    // 執(zhí)行invoke方法的類
    MethodAccessor ma = methodAccessor;             // read volatile
    if (ma == null) {
        ma = acquireMethodAccessor();
    }
    return ma.invoke(obj, args);
}

MethodAccessor有兩個(gè)最終實(shí)現(xiàn)類,一個(gè)是DelegatingMethodAccessorImpl,一個(gè)是NativeMethodAccessorImpl

NativeMethodAccessorImpl的源碼

class NativeMethodAccessorImpl extends MethodAccessorImpl {
    private final Method method;
    // 這個(gè)parent就是DelegatingMethodAccessorImpl
    private DelegatingMethodAccessorImpl parent;
    private int numInvocations;

    NativeMethodAccessorImpl(Method var1) {
        this.method = var1;
    }

    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);
    }

    void setParent(DelegatingMethodAccessorImpl var1) {
        this.parent = var1;
    }

    private static native Object invoke0(Method var0, Object var1, Object[] var2);
}

DelegatingMethodAccessorImpl的源碼。

``

class DelegatingMethodAccessorImpl extends MethodAccessorImpl {
        // delegate就是具體的實(shí)現(xiàn)方式,如果是本地實(shí)現(xiàn),這個(gè)成員變量指向的就是NativeMethodAccessorImpl對(duì)象,如果是動(dòng)態(tài)實(shí)現(xiàn),就會(huì)指向MethodAccessorGenerator對(duì)象
    private MethodAccessorImpl delegate;

    DelegatingMethodAccessorImpl(MethodAccessorImpl var1) {
        this.setDelegate(var1);
    }
        // 這里直接調(diào)用delegate對(duì)象的invoke方法。
    public Object invoke(Object var1, Object[] var2) throws IllegalArgumentException, InvocationTargetException {
        return this.delegate.invoke(var1, var2);
    }

    void setDelegate(MethodAccessorImpl var1) {
        this.delegate = var1;
    }
}

我們知道,執(zhí)行invoke()方法的是這行代碼生成的對(duì)象

// 執(zhí)行invoke方法的類
MethodAccessor ma = methodAccessor;             // read volatile
if (ma == null) {
ma = acquireMethodAccessor();
}

我們追到acquireMethodAccessor()方法里的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;
    }
}

可以看到,方法返回的是DelegatingMethodAccessorImpl,然后new一個(gè)NativeMethodAccessorImpl賦值給

DelegatingMethodAccessorImpl的delegate變量,同時(shí),把DelegatingMethodAccessorImpl賦值給NativeMethodAccessorImpl的parent變量。

那么我們明白了,執(zhí)行反射的時(shí)候,初始化會(huì)new一個(gè)DelegatingMethodAccessorImpl代理,然后new一個(gè)NativeMethodAccessorImpl賦值給DelegatingMethodAccessorImpl的delegate成員變量。真正執(zhí)行的就是這個(gè)delegate所指向的對(duì)象。由于這個(gè)對(duì)象是NativeMethodAccessorImpl,所以我們看一下NativeMethodAccessorImpl的invoke方法。

``

public Object invoke(Object var1, Object[] var2) throws IllegalArgumentException, InvocationTargetException {
        // 當(dāng)本地實(shí)現(xiàn)調(diào)用次數(shù)大于15次
    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);
}

我們可以看到一個(gè)判斷,大于15次調(diào)用,會(huì)new一個(gè)MethodAccessorGenerator對(duì)象賦值給delegate變量,當(dāng)下一次走到MethodAccessor.invoke(obj, args)方法時(shí),此時(shí)DelegatingMethodAccessorImpl的delegate對(duì)象已經(jīng)指向了MethodAccessorGenerator,所以后面再調(diào)用反射,走的就是動(dòng)態(tài)生成代碼的實(shí)現(xiàn)。MethodAccessorGenerator是直接生成字節(jié)碼的實(shí)現(xiàn),比較快。

我們來捋一捋,開始調(diào)用走的是NativeMethodAccessorImpl的invoke方法,再調(diào)用invoke0這個(gè)native方法,第15次時(shí),new一個(gè)MethodAccessorGenerator,然后繼續(xù)走invoke0,當(dāng)?shù)?6次時(shí),調(diào)用就走的是MethodAccessorGenerator,生成字節(jié)碼是個(gè)耗時(shí)的操作,所以反射的第15次調(diào)用是最慢的,這次調(diào)用不僅動(dòng)態(tài)生成了字節(jié)碼,還走了JNI調(diào)用。

# 總結(jié)

  1. NativeMethodAccessorImpl調(diào)用的是JNI,也就是native方法,這是c++代碼,在C++里又調(diào)用java代碼,所以本地實(shí)現(xiàn)是java到c++再到j(luò)ava的過程,比較慢,而MethodAccessorGenerator是通過ASM動(dòng)態(tài)生成字節(jié)碼的方式。
  2. 這里想跟大家提一個(gè)概念,大家都是生成字節(jié)碼,憑什么你比我的快?其實(shí)生成的字節(jié)碼是有區(qū)別的。通過走NativeMethodAccessorImpl編譯執(zhí)行的代碼,是被jvm虛擬機(jī)識(shí)別的字節(jié)碼,不能被硬件機(jī)器識(shí)別,這種字節(jié)碼被虛擬機(jī)通過解釋執(zhí)行,而MethodAccessorGenerator生成的字節(jié)碼,是可以直接跑在機(jī)器上的指令,所以比較快。當(dāng)然,還有一些其他的原因,感興趣的小伙伴可以去了解一下什么是解釋執(zhí)行和即時(shí)編譯,什么是方法內(nèi)聯(lián),什么是對(duì)象逃逸。
  3. 這個(gè)閾值 15(可以通過 -Dsun.reflect.inflationThreshold= 來調(diào)整)
  4. 這個(gè)源碼相對(duì)來說類比較少,方法單一,大家可以自己debug走一遍。

參考

GeekTime-鄭雨迪的《深入拆解Java虛擬機(jī)》的反射章節(jié)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容