美文网首页
java反射

java反射

作者: 泽林呗 | 来源:发表于2019-03-10 23:41 被阅读0次

    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反射

          本文链接:https://www.haomeiwen.com/subject/fogupqtx.html