java反射

Method.invoke实际上是委派给MethodAccessor来实现,它有两种具体实现,一个通过本地方法来实现反射调用,一个则使用了委派模式

  MethodAccessor ma = methodAccessor;             // read volatile
        if (ma == null) {
            ma = acquireMethodAccessor();
        }
        return ma.invoke(obj, args);

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class Test {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        Class klass = Class.forName("Test");
        //每个Method实例的第一次反射调用都会生成一个委派实现,它所委派的具体实现便是一个本地实现。
        Method method = klass.getMethod("target", int.class);
        method.invoke(null, 0);
    }

    public static void target(int i) {
        //我们打印反射调用的栈轨迹
        new Exception("#" + i).printStackTrace();
    }
}

java.lang.Exception: #0
at Test.target(Test.java:12)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at Test.main(Test.java:8)

调用过程:Method.invoke->DelegatingMethodAccessorImpl->NativeMethodAccessorlmpl->本地方法

为什么

为什么反射调用还要采取委派实现作为中间层 (Inflation过程)
其实,java的反射调用机制还设立了另一种动态生成字节码的实现(动态实现),直接使用invoke指令来调用目标方法。之所以采用委派实现,便是为了能够在本地实现以及动态实现中切换,动态实现比本地实现快20倍,这是因为动态实现无需经过java到c++到java的切换,但由于生成字节码比较耗时,仅调用一次的话,还是本地实现快上3到4倍

解决思路

设立阈值:Dsun.reflect.inflation.ThresHold = 15
if >= 15 委派给动态实现 (从0开始数)
if < 15 委派给本地实现

java.lang.Exception: #15
at Test.target(Test.java:17)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at Test.main(Test.java:11)
java.lang.Exception: #16
at Test.target(Test.java:17)
at sun.reflect.GeneratedMethodAccessor1.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at Test.main(Test.java:11)

Inflation过程可通过参数:-Dsun.reflect.noInflation=true关闭,这样就不会使用委派模式和本地实现,直接动态实现

你可能感兴趣的:(java反射)