精华内容
下载资源
问答
  • invoke方法
    千次阅读
    2022-06-08 20:37:14

    invoke的本意即为调用,而在Java中,我们可以通过invoke方法来反射获取成员方法并调用

     invoke方法的使用
    普通情况下调用方法的步骤为:new一个对象A,若调用A中的method方法则A.method

    使用invoke方法时:我们需要创建一个目标对象的替代对象(即Method对象),传给替代对象相应的参数使用替代对象进行方法的调用

    所以使用invoke方法要比别的方法多做一步,就是构建一个Method对象,这个对象替代的是现在程序要调用方法的替代品。

    更多相关内容
  • java动态代理中的invoke方法

    千次阅读 2021-07-08 14:46:39
    //这就是动态代理的好处 被封装的对象是Object类型 接受任意类型的对象 //这个方法不是我们 显示的去调用 @Override //而这个invoke方法就是在主函数 调用了sb.request方法时,就调用了Proxy类的request方法 //进而...

    前言

    记录一篇好的文章
    https://blog.csdn.net/zcc_0015/article/details/22695647
    同时推荐狂神说的视频,对于动态代理讲解的很详细
    https://www.bilibili.com/video/BV1WE411d7Dv?p=19

    一、动态代理与静态代理的区别

    (1)Proxy类的代码被固定下来,不会因为业务的逐渐庞大而庞大;
    (2)可以实现AOP编程,这是静态代理无法实现的;
    (3)解耦,如果用在web业务下,可以实现数据层和业务层的分离。
    (4)动态代理的优势就是实现无侵入式的代码扩展。
    静态代理这个模式本身有个大问题,如果类方法数量越来越多的时候,代理类的代码量是十分庞大的。所以引入动态代理来解决此类问题

    二、动态代理

    Java中动态代理的实现,关键就是这两个东西:Proxy、InvocationHandler,下面从InvocationHandler接口中的invoke方法入手,简单说明一下Java如何实现动态代理的。
    首先,invoke方法的完整形式如下:

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable  
    {  
    method.invoke(obj, args);  
    
        return null;  
    }  
    
    

    首先猜测一下,method是调用的方法,即需要执行的方法;args是方法的参数;proxy,这个参数是什么?以上invoke()方法的实现即是比较标准的形式,我们看到,这里并没有用到proxy参数。查看JDK文档中Proxy的说明,如下:

    A method invocation on a proxy instance through one of its proxy interfaces will be dispatched to the invoke method of the instance's invocation handler, passing the proxy instance,a java.lang.reflect.Method object identifying the method that was invoked, and an array of type Object containing the arguments.  
    
    

    由此可以知道以上的猜测是正确的,同时也知道,proxy参数传递的即是代理类的实例。
    为了方便说明,这里写一个简单的例子来实现动态代理。

    package TestProxy;
    
    public interface Subject {
        public void request();
    }
    
    
    package TestProxy;
    
    //真实角色
    public class RealSubject implements Subject{
        @Override
        public void request() {
            System.out.println("From real subject");
        }
    }
    
    
    package TestProxy;
    
    import lombok.AllArgsConstructor;
    import lombok.NoArgsConstructor;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    
    //实现InvocationHandler
    //这两个注解 就生成了无参和全参的构造函数
    @AllArgsConstructor
    @NoArgsConstructor
    public class DynamicSubject implements InvocationHandler {
        private Object obj;//这就是动态代理的好处 被封装的对象是Object类型 接受任意类型的对象
        //这个方法不是我们 显示的去调用
        @Override
        //而这个invoke方法就是在主函数 调用了sb.request方法时,就调用了Proxy类的request方法
        //进而调用了父类中的Proxy的invoke方法
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("before calling "+method);
            //这个我还是不知道呀。。。
            //首先要理解的就是 method.invoke 我理解为 invoke method 也就是激活对应的方法
            //而这里 对应的的方法就是 realSubject中的getRequest
            //method一直都是 public abstract void TestProxy.Subject.request()
            method.invoke(obj,args);
            //再看看这两个
            System.out.println("obj是:"+obj);
            System.out.println("args是:"+args);
            //这个真的是个祸害 一用就会疯狂报错 还真如博主所说的
           // 看来,这个proxy参数并没有什么作用,在整个动态代理机制中,并没有用到InvocationHandler中invoke方法的proxy参数。而传入的这个参数实际是代理类的一个实例。我想可能是为了让程序员在invoke方法中使用反射来获取关于代理类的一些信息吧
           //这个的结果是com.sun.proxy.$Proxy0
            //可以将代理对象返回以进行连续调用
            System.out.println("proxy是:"+proxy.getClass().getName());
            System.out.println("after calling "+method);
            return null;
        }
    }
    
    
    package TestProxy;
    
    import com.sun.scenario.effect.impl.sw.sse.SSEBlend_SRC_OUTPeer;
    
    import java.lang.reflect.Field;
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    
    //他生成了代理的实例 并且调用了request()方法
    public class Client {
        public static void main(String[] args) {
            //这个是被代理的类
            Subject rs=new RealSubject();
            //生成代理类
            InvocationHandler ds=new DynamicSubject(rs);
    
            //这里是得到一系列的类
            Class<?> cls=rs.getClass();
            //下面是一次性生成代理
            //直接通过Proxy生成一个代理 并且其中三个参数 都是来自class的 classloader interfaces和一个invocationHandler
            Subject sb= (Subject) Proxy.newProxyInstance(cls.getClassLoader(), cls.getInterfaces(),ds);
    
            //sb instanceof Proxy这是啥意思
            //这里可以通过运行结果证明subject是Proxy的一个实例,这个实例实现了Subject接口
            //原来 instanceof真的可以和==一样
            System.out.println(sb instanceof Proxy);
    
            //这里可以看出subject的Class类是$Proxy0,这个$Proxy0类继承了Proxy,实现了Subject接口
            System.out.println("sbd的Class类是" +sb.getClass().toString());
    
            System.out.println("sb中的属性有: ");
    
            //这几个getFields代表什么意思呢 getFields是获得所有公共 public的字段,getDeclareFields
            //是获得所有声明的字段 包括private  因为Declared的意思就是 “已经声明”
            Field[] fields=sb.getClass().getFields();
            for(Field field:fields){
                System.out.println("getFields的对应:"+field.getName());
            }
    
            System.out.println("\n"+"sb中的方法有:");
            Method[] methods=sb.getClass().getMethods();
            for(Method method:methods){
                System.out.println("method的对应:"+method.getName());
            }
    
            System.out.println("\n"+"sb的父类是"+sb.getClass().getSuperclass());
    
            System.out.println("\n"+"sb实现的接口是: ");
            Class<?>[] interfaces=sb.getClass().getInterfaces();
    
            for(Class<?> interfaceName:interfaces){
                System.out.println("interface的对应是:"+interfaceName.getName());
            }
    
            System.out.println("\n"+"运行结果为:");
            //sb一直都是class com.sun.proxy.$Proxy0
            //他的父类是 class java.lang.reflect.Proxy
            //可以看一下 这两个有什么区别
            //还有个问题 就是 从什么时候开始 sb有这个request方法了。。
            //是因为sb是一个Subject类然后是代理类 强制转换成Subject类,所以他存在这个方法
            sb.request();
    
        }
    }
    
    

    运行结果

    true
    sbd的Class类是class com.sun.proxy.$Proxy0
    sb中的属性有: 
    
    sb中的方法有:
    method的对应:equals
    method的对应:toString
    method的对应:hashCode
    method的对应:request
    method的对应:isProxyClass
    method的对应:newProxyInstance
    method的对应:getInvocationHandler
    method的对应:getProxyClass
    method的对应:wait
    method的对应:wait
    method的对应:wait
    method的对应:getClass
    method的对应:notify
    method的对应:notifyAll
    
    sb的父类是class java.lang.reflect.Proxy
    
    sb实现的接口是: 
    interface的对应是:TestProxy.Subject
    
    运行结果为:
    before calling public abstract void TestProxy.Subject.request()
    From real subject
    obj是:TestProxy.RealSubject@1bbe9ba
    args是:null
    proxy是:com.sun.proxy.$Proxy0
    after calling public abstract void TestProxy.Subject.request()
    
    

    PS:这个结果的信息非常重要,至少对我来说。因为我在动态代理犯晕的根源就在于将上面的subject.request()理解错了,至少是被表面所迷惑,没有发现这个subject和Proxy之间的联系,一度纠结于最后调用的这个request()是怎么和invoke()联系上的,而invoke又是怎么知道request存在的。其实上面的true和class P r o x y ProxyProxy就能解决很多的疑问,再加上下面将要说的P r o x y ProxyProxy的源码,完全可以解决动态代理的疑惑了。

    从以上代码和结果可以看出,我们并没有显示的调用invoke()方法,但是这个方法确实执行了。下面就整个的过程进行分析一下:

    从Client中的代码看,可以从newProxyInstance这个方法作为突破口,我们先来看一下Proxy类中newProxyInstance方法的源代码:

    public static Object newProxyInstance(ClassLoader loader,  
            Class<?>[] interfaces,  
            InvocationHandler h)  
    throws IllegalArgumentException  
    {  
        if (h == null) {  
            throw new NullPointerException();  
        }  
      
        /* 
         * Look up or generate the designated proxy class. 
         */  
        Class cl = getProxyClass(loader, interfaces);  
      
        /* 
         * Invoke its constructor with the designated invocation handler. 
         */  
        try {  
               /* 
                * Proxy源码开始有这样的定义: 
                * private final static Class[] constructorParams = { InvocationHandler.class }; 
                * cons即是形参为InvocationHandler类型的构造方法 
               */  
            Constructor cons = cl.getConstructor(constructorParams);  
            return (Object) cons.newInstance(new Object[] { h });  
        } catch (NoSuchMethodException e) {  
            throw new InternalError(e.toString());  
        } catch (IllegalAccessException e) {  
            throw new InternalError(e.toString());  
        } catch (InstantiationException e) {  
            throw new InternalError(e.toString());  
        } catch (InvocationTargetException e) {  
            throw new InternalError(e.toString());  
        }  
    }  
    
    
            Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)做了以下几件事.1)根据参数loader和interfaces调用方法 getProxyClass(loader, interfaces)创建代理类$Proxy0.$Proxy0类 实现了interfaces的接口,并继承了Proxy类.2)实例化$Proxy0并在构造方法中把DynamicSubject传过去,接着$Proxy0调用父类Proxy的构造器,为h赋值,如下: 
    Java代码  收藏代码
    class Proxy{  
        InvocationHandler h=null;  
        protected Proxy(InvocationHandler h) {  
            this.h = h;  
        }  
        ...  
    }  
    
    

    来看一下这个继承了Proxy的P r o x y ProxyProxy的源代码:

    public final class $Proxy0 extends Proxy implements Subject {  
        private static Method m1;  
        private static Method m0;  
        private static Method m3;  
        private static Method m2;  
      
        static {  
            try {  
                m1 = Class.forName("java.lang.Object").getMethod("equals",  
                        new Class[] { Class.forName("java.lang.Object") });  
      
                m0 = Class.forName("java.lang.Object").getMethod("hashCode",  
                        new Class[0]);  
      
                m3 = Class.forName("***.RealSubject").getMethod("request",  
                        new Class[0]);  
      
                m2 = Class.forName("java.lang.Object").getMethod("toString",  
                        new Class[0]);  
      
            } catch (NoSuchMethodException nosuchmethodexception) {  
                throw new NoSuchMethodError(nosuchmethodexception.getMessage());  
            } catch (ClassNotFoundException classnotfoundexception) {  
                throw new NoClassDefFoundError(classnotfoundexception.getMessage());  
            }  
        } //static  
      
        public $Proxy0(InvocationHandler invocationhandler) {  
            super(invocationhandler);  
        }  
      
        @Override  
        public final boolean equals(Object obj) {  
            try {  
                return ((Boolean) super.h.invoke(this, m1, new Object[] { obj })) .booleanValue();  
            } catch (Throwable throwable) {  
                throw new UndeclaredThrowableException(throwable);  
            }  
        }  
      
        @Override  
        public final int hashCode() {  
            try {  
                return ((Integer) super.h.invoke(this, m0, null)).intValue();  
            } catch (Throwable throwable) {  
                throw new UndeclaredThrowableException(throwable);  
            }  
        }  
      
        public final void request() {  
            try {  
                super.h.invoke(this, m3, null);  
                return;  
            } catch (Error e) {  
            } catch (Throwable throwable) {  
                throw new UndeclaredThrowableException(throwable);  
            }  
        }  
      
        @Override  
        public final String toString() {  
            try {  
                return (String) super.h.invoke(this, m2, null);  
            } catch (Throwable throwable) {  
                throw new UndeclaredThrowableException(throwable);  
            }  
        }  
    }  
    
    

    接着把得到的P r o x y ProxyProxy实例强制转换成Subject,并将引用赋给subject。当执行subject.request()方法时,就调用了P r o x y ProxyProxy类中的request()方法,进而调用父类Proxy中的h的invoke()方法.即InvocationHandler.invoke()。

    PS:1、需要说明的一点是,Proxy类中getProxyClass方法返回的是Proxy的Class类。之所以说明,是因为我一开始犯了个低级错误,以为返回的是“被代理类的Class类”- -!推荐看一下getProxyClass的源码,很长=。=
    2、从$Proxy0的源码可以看出,动态代理类不仅代理了显示定义的接口中的方法,而且还代理了java的根类Object中的继承而来的equals()、hashcode()、toString()这三个方法,并且仅此三个方法。

    Q:到现在为止,还有一个疑问,invoke方法中的第一个参数是Proxy的实例(准确说,最终用到的是$Proxy0的实例),但是有什么用呢?或者说,程序内是怎样显示出作用的?
    A:就本人目前的水平看来,这个proxy参数并没有什么作用,在整个动态代理机制中,并没有用到InvocationHandler中invoke方法的proxy参数。而传入的这个参数实际是代理类的一个实例。我想可能是为了让程序员在invoke方法中使用反射来获取关于代理类的一些信息吧。

    原文链接
    https://blog.csdn.net/zcc_0015/article/details/22695647

    展开全文
  • JAVA的Invoke方法

    千次阅读 2021-08-26 11:18:53
    如果读一些Java或者相关框架的源码,实际上一定会经常出现invoke方法的调用,在自己或者团队封装框架时,如果有时候弄得不好经常也会报invoke相关的错。 invoke方法是干什么的?有什么具体用途? 首先要了解invoke...

    如果读一些Java或者相关框架的源码,实际上一定会经常出现invoke方法的调用,在自己或者团队封装框架时,如果有时候弄得不好经常也会报invoke相关的错。

    invoke方法是干什么的?有什么具体用途?

    首先要了解invoke方法干什么的以及具体用途,实际你要搞清他在源码那个class文件上,他在那个包里,追根溯源。

    invoke方法来自Method类,可能不会像我们经常用到的基础类型包装类,以及集合类还有他们的扩展和工具类使用的那么多。

    但是Method类所在的包可是大名鼎鼎的反射Reflact,不是有一句话Java没有反射,那么很多框架都不会存在。

    我们经常new 对象出来,但是new的前提是你知道你到底需要什么对象,你才能new,然而不管是代码还是现实生活都有未知性,也就是直到程序运行时受条件限制才知道什么类,什么方法。

    反射解决的这个问题,运行时获取对象结构,调用方法。
    Method这个类就是关于反射调用方法的
    下图是Method类的官方注解


    大概意思就是说提供类或者接口的方法信息,就可以访问调用对应的方法。

    invoke的意思上就有调用的意思,也就是说我们可以通过反射包下的Method类调用invoke方法,调用我们所提供的方法以及调用方法的参数来完成动态调用。

    也就是根据你给的对象/实例,方法名,以及参数来调用。找了个“替身”来帮你调用方法。

    2 invoke方法的使用
    实际上invoke方法的使用,和我们常见的有所区别。

    我们经常创建一个对象A,A对象里面的方法getA()方法,然后A.getA()

    我们采用新的方式调用
    (1)弄一个方法的“替身”(其实就是构建一个Method对象,让这个Method对象来代替你现在要用的方法)
    (2)然后给替身需要的对象和参数,让替身去替你调用(像JOJO的替身替你去战斗)

    具体代码演示如下:

    public class InvokeTest {
        public void test(String[] arg){
            for (String string : arg) {
                System.out.println("zp is " + string);
            }
        }
        @Test
        public void invokeDemo() throws Exception {
            //获取字节码对象,这里要填好你对应对象的包的路径
            Class<InvokeTest> clazz = (Class<InvokeTest>) Class.forName("com.example.zp.demo.testDemo.InvokeTest");
            //形式一:获取一个对象
    //        Constructor con =  clazz.getConstructor();
    //        InvokeTest m = (InvokeTest) con.newInstance();
            //形式二:直接new对象,实际上不是框架的话,自己写代码直接指定某个对象创建并调用也可以
            InvokeTest m = new InvokeTest();
            String[] s = new String[]{"handsome","smart"};
            //获取Method对象
            Method method = clazz.getMethod("test", String[].class);
            //调用invoke方法来调用
            method.invoke(m, (Object) s);
        }

    所以使用invoke方法要比别的方法多做一步,就是构建一个Method对象,这个对象替代的是现在程序要调用方法的替代品。

    而且除了参数以外,invoke还会多要一个对象,因为方法调用需要对象,所以invoke要想调用的目标方法,就需要目标方法的需要的对象。

    看起来invoke方法不仅比平常方法直接调用要麻烦很多,但是你有想过吗,我只需要输入参数,我可以调用替代各种方法,在未知的情况下,根据条件决定去调用什么对象,什么方法,一下子就让代码变得灵活,这不仅是invoke的妙处,也是整个反射的妙处,在程序运行时根据条件灵活使用。

    展开全文
  • 主要介绍了Java Method类及invoke方法原理解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
  • 各位大佬求指导,按EasyExcel官方文档上写个读文件,但是怎么都读不到,不进invoke方法,页面error日志,debug跟代码发现有com.alibaba.excel.exception.ExcelAnalysisStopException这个异常,但是自己底层捕获了,...
  • java反射之Method的invoke方法实现

    万次阅读 多人点赞 2018-07-29 00:31:48
    然而前段时间研究invoke方法时,发现invoke方法居然包含多态的特性,这是以前没有考虑过的一个问题。那么Method.invoke()方法的执行过程是怎么实现的?它的多态又是如何实现的呢? 本文将从java和JVM...

    在框架中经常会会用到method.invoke()方法,用来执行某个的对象的目标方法。以前写代码用到反射时,总是获取先获取Method,然后传入对应的Class实例对象执行方法。然而前段时间研究invoke方法时,发现invoke方法居然包含多态的特性,这是以前没有考虑过的一个问题。那么Method.invoke()方法的执行过程是怎么实现的?它的多态又是如何实现的呢?

    本文将从java和JVM的源码实现深入探讨invoke方法的实现过程。

    首先给出invoke方法多态特性的演示代码:

    public class MethodInvoke {
    
    	public static void main(String[] args) throws Exception {
    		Method animalMethod = Animal.class.getDeclaredMethod("print");
    		Method catMethod = Cat.class.getDeclaredMethod("print");
    		
    		Animal animal = new Animal();
    		Cat cat = new Cat();
    		animalMethod.invoke(cat);
    		animalMethod.invoke(animal);
    		
    		catMethod.invoke(cat);
    		catMethod.invoke(animal);
    	}
    	
    }
    
    class Animal {
    	
    	public void print() {
    		System.out.println("Animal.print()");
    	}
    	
    }
    
    class Cat extends Animal {
    	
    	@Override
    	public void print() {
    		System.out.println("Cat.print()");
    	}
    	
    }

    代码中,Cat类覆盖了父类Animal的print()方法, 然后通过反射分别获取print()的Method对象。最后分别用Cat和Animal的实例对象去执行print()方法。其中animalMethod.invoke(animal)和catMethod.invoke(cat),示例对象的真实类型和Method的声明Classs是相同的,按照预期打印结果;animalMethod.invoke(cat)中,由于Cat是Animal的子类,按照多态的特性,子类调用父类的的方法,方法执行时会动态链接到子类的实现方法上。因此,这里会调用Cat.print()方法;而catMethod.invoke(animal)中,传入的参数类型Animal是父类,却期望调用子类Cat的方法,因此这一次会抛出异常。代码打印结果为:

    Cat.print()
    Animal.print()
    Cat.print()
    Exception in thread "main" java.lang.IllegalArgumentException: object is not an instance of declaring class
    	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    	at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    	at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    	at java.lang.reflect.Method.invoke(Unknown Source)
    	at com.wy.invoke.MethodInvoke.main(MethodInvoke.java:17)

    接下来,我们来看看invoke()方法的实现过程。

        public Object invoke(Object obj, Object... args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException
        {
            if (!override) {
                if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
                    Class<?> caller = Reflection.getCallerClass(1);
    
                    checkAccess(caller, clazz, obj, modifiers);
                }
            }
            MethodAccessor ma = methodAccessor;             // read volatile
            if (ma == null) {
                ma = acquireMethodAccessor();
            }
            return ma.invoke(obj, args);
        }
    

    invoke()方法中主要分为两部分:访问控制检查和调用MethodAccessor.invoke()实现方法执行。

    首先看一下访问控制检查这一块的逻辑。第一眼看到这里的逻辑的时候,很容易搞不清楚是干嘛的。通俗来讲就是通过方法的修饰符(public/protected/private/package),来判断方法的调用者是否可以访问该方法。这是java的基础内容,不过用代码写出来,一下子不容易想到。访问控制检查分为3步:

    1. 检查override,如果override为true,跳过检查;否则继续;
    2. 快速检查,判断该方法的修饰符modifiers是否为public,如果是跳过检查;否则继续;
    3. 详细检查,通过方法的(protected/private/package)修饰符或方法的声明类(例如子类可以访问父类的protected方法)与调用者caller之间的关系,判断caller是否有权限访问该方法。

    override属性是Method的父类AccessibleObject中声明的变量,使得程序可以控制是否跳过访问权限的检查。另外,Method的实例对象中,override属性的初始值设置为false。

        public void setAccessible(boolean flag) throws SecurityException {
            SecurityManager sm = System.getSecurityManager();
            if (sm != null) sm.checkPermission(ACCESS_PERMISSION);
            setAccessible0(this, flag);
        }
    
        private static void setAccessible0(AccessibleObject obj, boolean flag)
            throws SecurityException
        {
            if (obj instanceof Constructor && flag == true) {
                Constructor<?> c = (Constructor<?>)obj;
                if (c.getDeclaringClass() == Class.class) {
                    throw new SecurityException("Can not make a java.lang.Class" +
                                                " constructor accessible");
                }
            }
            obj.override = flag;
        }

    多说一句,Field同样继承了AccessibleObject,且Field的override也是初始化为false的,也就是说并没有按照变量的修饰符去初始化不同的值。但是我们在调用Field.set(Object obj, Object value)时,如果该Field是private修饰的,会因没有访问权限而抛出异常,因此必须调用setAccessible(true)。此处非常容易理解为因为变量是public的,所以override就被初始化为true。

    invoke()方法中,访问控制检查之后,就是通过MethodAccessor.invoke()调用方法。再来看一下代码:

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

    这里的逻辑很简单,首先将变量methodAccessor赋值给ma,在方法栈中保存一个可以直接引用的本地变量,如果methodAccessor不存在,调用acquireMethodAccessor()方法创建一个。

        private volatile MethodAccessor methodAccessor;
        private Method root;
        
        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;
        }
    
        void setMethodAccessor(MethodAccessor accessor) {
            methodAccessor = accessor;
            // Propagate up
            if (root != null) {
                root.setMethodAccessor(accessor);
            }
        }
    
        Method copy() {
            Method res = new Method(clazz, name, parameterTypes, returnType,
                                    exceptionTypes, modifiers, slot, signature,
                                    annotations, parameterAnnotations, annotationDefault);
            res.root = this;
            res.methodAccessor = methodAccessor;
            return res;
        }

    综合acquireMethodAccessor(),setMethodAccessor()以及copy()这三个方法,可以看到一个Method实例对象维护了一个root引用。当调用Method.copy()进行方法拷贝时,root指向了被拷贝的对象。那么当一个Method被多次拷贝后,调用一次setMethodAccessor()方法,就会将root引用所指向的Method的methodAccessor变量同样赋值。例如:D -> C -> B -> A,其中X-> Y表示X = Y.copy(), 当C对象调用setMethodAccessor()时,B和A都会传播赋值methodAccessor, 而D的methodAccessor还是null。紧接着,当D需要获取methodAccessor而调用acquireMethodAccessor()时,D获取root的methodAccessor, 那么D将和ABC持有相同的methodAccessor。

    虽然Method中,通过维护root引用意图使相同的方法始终保持只有一个methodAccessor实例,但是上述方法仍然无法保证相同的方法只有一个methodAccessor实例。例如通过copy()使ABCD保持关系:D -> C -> B -> A, 当B对象调用setMethodAccessor()时,B和A都会赋值methodAccessor, 而C、D的methodAccessor还是null。这时D调用acquireMethodAccessor()时,D获取root也就是C的methodAccessor,发现为空,然后就新创建了一个。从而出现了相同的方法中出现了两个methodAccessor实例对象的现象。

    在Class.getMethod()、Class.getDeclaredMethod()以及Class.getDeclaredMethod(String name, Class<?>... parameterTypes)方法中最终都会调用copy()方法来保障Method使用的安全性。 在比较极端加巧合的情况下,可能会引起类膨胀的问题,这就是接下来要讲到的MethodAccessor的实现机制。

    copy

    在前面代码中,MethodAccessor的创建是通过反射工厂ReflectionFactory的newMethodAccessor(Method)方法来创建的。

        public MethodAccessor newMethodAccessor(Method method) {
            checkInitted();
    
            if (noInflation) {
                return new MethodAccessorGenerator().
                    generateMethod(method.getDeclaringClass(),
                                   method.getName(),
                                   method.getParameterTypes(),
                                   method.getReturnType(),
                                   method.getExceptionTypes(),
                                   method.getModifiers());
            } else {
                NativeMethodAccessorImpl acc =
                    new NativeMethodAccessorImpl(method);
                DelegatingMethodAccessorImpl res =
                    new DelegatingMethodAccessorImpl(acc);
                acc.setParent(res);
                return res;
            }
        }

    其中, checkInitted()方法检查从配置项中读取配置并设置noInflation、inflationThreshold的值:

        private static void checkInitted() {
            if (initted) return;
            AccessController.doPrivileged(
                new PrivilegedAction<Void>() {
                    public Void run() {
    
                        if (System.out == null) {
                            // java.lang.System not yet fully initialized
                            return null;
                        }
    
                        String val = System.getProperty("sun.reflect.noInflation");
                        if (val != null && val.equals("true")) {
                            noInflation = true;
                        }
    
                        val = System.getProperty("sun.reflect.inflationThreshold");
                        if (val != null) {
                            try {
                                inflationThreshold = Integer.parseInt(val);
                            } catch (NumberFormatException e) {
                                throw (RuntimeException)
                                    new RuntimeException("Unable to parse property sun.reflect.inflationThreshold").
                                        initCause(e);
                            }
                        }
    
                        initted = true;
                        return null;
                    }
                });
        }

    可以通过启动参数-Dsun.reflect.noInflation=false -Dsun.reflect.inflationThreshold=15来设置:

    结合字面意思及下面代码理解,这两个配置sun.reflect.noInflation是控制是否立即进行类膨胀,sun.reflect.inflationThreshold是设置类膨胀阈值。

    创建MethodAccessor有两种选择,一种是当sun.reflect.noInflation配置项为true时,ReflectionFactory利用MethodAccessor的字节码生成类 MethodAccessorGenerator直接创建一个代理类,通过间接调用原方法完成invoke()任务,具体实现稍后给出。MethodAccessor的另一种实现方式是,创建DelegatingMethodAccessorImpl 委托类,并将执行invoke()方法的具体内容交由NativeMethodAccessorImpl实现,而NativeMethodAccessorImpl最终调用native方法完成invoke()任务。以下是NativeMethodAccessorImpl的invoke()方法实现。

        public Object invoke(Object obj, Object[] args) 
            throws IllegalArgumentException, InvocationTargetException
        {
            if (++numInvocations > ReflectionFactory.inflationThreshold()) {
                MethodAccessorImpl acc = (MethodAccessorImpl)
                    new MethodAccessorGenerator().
                        generateMethod(method.getDeclaringClass(),
                                       method.getName(),
                                       method.getParameterTypes(),
                                       method.getReturnType(),
                                       method.getExceptionTypes(),
                                       method.getModifiers());
                parent.setDelegate(acc);
            }
    
            return invoke0(method, obj, args);
        }
    
        private static native Object invoke0(Method m, Object obj, Object[] args);

    可以看到,当numInvocations数量大于配置项sun.reflect.inflationThreshold即类膨胀阈值时, 使用MethodAccessorGenerator创建一个代理类对象,并且将被委托的NativeMethodAccessorImpl的parent,也就是委托类DelegatingMethodAccessorImpl的委托类设置为这个生成的代理对象。这么说可能有点绕,下面用一幅图表示这个过程。

    delegate

    总体来说,当调用invoke()时,按照默认配置,Method首先创建一个DelegatingMethodAccessorImpl对象,并设置一个被委托的NativeMethodAccessorImpl对象,那么method.invoke()就被转换成DelegatingMethodAccessorImpl.invoke(),然后又被委托给NativeMethodAccessorImp.invoke()实现。当NativeMethodAccessorImp.invoke()调用次数超过一定热度时(默认15次),被委托方又被转换成代理类来实现。

    之前提到过在极端情况下,同一个方法的Method对象存在多个不同拷贝拷贝时,可能存在多个MethodAccessor对象。那么当多次调用后,必然会生成两个重复功能的代理类。当然,一般情况下,生成两个代理类并没有较大的影响。

    其中代理类的具体字节码实现过程较为复杂,大体思想是生成一个如下所示的类:

    public class GeneratedMethodAccessor1 extends MethodAccessorImpl {
    
    	public GeneratedMethodAccessor1 () {
    	    super();
    	}
    	
    	public Object invoke(Object obj, Object[] args)
    	        throws IllegalArgumentException, InvocationTargetException 
    	{
    		if (!(obj instanceof Cat)) {
    			throw new ClassCastException();
    		}
    		if (args != null && args.length != 0) {
    			throw new IllegalArgumentException();
    		}
    		
    		try {
    			Cat cat = (Cat) obj;
    			cat.print();
    			return null;
    		} catch (Throwable e) {
    			throw new InvocationTargetException(e, "invoke error");
    		}
    	}
    	
    }

    到目前为止,除了在代理的GeneratedMethodAccessor1 类中,方法的执行有多态的特性,而NativeMethodAccessorImp的invoke()实现是在jdk中的完成的。接下来我们将目光移到NativeMethodAccessorImp的native方法invoke0();

    openJDK下载地址

    首先,在\jdk\src\share\native\sun\reflect路径下找到NativeAccessors.c, 其中有Java_sun_reflect_NativeMethodAccessorImpl _invoke0()方法,根据JNI定义函数名的规则"包名_类名_方法名",这就是我们要找的native方法实现入口。

    JNIEXPORT jobject JNICALL Java_sun_reflect_NativeMethodAccessorImpl_invoke0
    (JNIEnv *env, jclass unused, jobject m, jobject obj, jobjectArray args)
    {
        return JVM_InvokeMethod(env, m, obj, args);
    }

    方法调用JVM_InvokeMethod(), 一般以JVM_开头的函数定义在jvm.cpp文件中,不熟悉的话可以通过头文件jvm.h看出来。继续追踪,发现jvm.cpp文件位于spot\src\share\vm\prims文件夹下。

    JVM_ENTRY(jobject, JVM_InvokeMethod(JNIEnv *env, jobject method, jobject obj, jobjectArray args0))
      JVMWrapper("JVM_InvokeMethod");
      Handle method_handle;
      if (thread->stack_available((address) &method_handle) >= JVMInvokeMethodSlack) {
        method_handle = Handle(THREAD, JNIHandles::resolve(method));
        Handle receiver(THREAD, JNIHandles::resolve(obj));
        objArrayHandle args(THREAD, objArrayOop(JNIHandles::resolve(args0)));
        oop result = Reflection::invoke_method(method_handle(), receiver, args, CHECK_NULL);
        jobject res = JNIHandles::make_local(env, result);
        if (JvmtiExport::should_post_vm_object_alloc()) {
          oop ret_type = java_lang_reflect_Method::return_type(method_handle());
          assert(ret_type != NULL, "sanity check: ret_type oop must not be NULL!");
          if (java_lang_Class::is_primitive(ret_type)) {
            // Only for primitive type vm allocates memory for java object.
            // See box() method.
            JvmtiExport::post_vm_object_alloc(JavaThread::current(), result);
          }
        }
        return res;
      } else {
        THROW_0(vmSymbols::java_lang_StackOverflowError());
      }
    JVM_END

    其中oop result = Reflection::invoke_method(method_handle(), receiver, args, CHECK_NULL)是方法的执行过程,在\hotspot\src\share\vm\runtime路径下找到reflection.cpp文件。

    oop Reflection::invoke_method(oop method_mirror, Handle receiver, objArrayHandle args, TRAPS) {
      oop mirror             = java_lang_reflect_Method::clazz(method_mirror);
      int slot               = java_lang_reflect_Method::slot(method_mirror);
      bool override          = java_lang_reflect_Method::override(method_mirror) != 0;
      objArrayHandle ptypes(THREAD, objArrayOop(java_lang_reflect_Method::parameter_types(method_mirror)));
    
      oop return_type_mirror = java_lang_reflect_Method::return_type(method_mirror);
      BasicType rtype;
      if (java_lang_Class::is_primitive(return_type_mirror)) {
        rtype = basic_type_mirror_to_basic_type(return_type_mirror, CHECK_NULL);
      } else {
        rtype = T_OBJECT;
      }
    
      instanceKlassHandle klass(THREAD, java_lang_Class::as_Klass(mirror));
      Method* m = klass->method_with_idnum(slot);
      if (m == NULL) {
        THROW_MSG_0(vmSymbols::java_lang_InternalError(), "invoke");
      }
      methodHandle method(THREAD, m);
    
      return invoke(klass, method, receiver, override, ptypes, rtype, args, true, THREAD);
    }
    
    oop Reflection::invoke(instanceKlassHandle klass, methodHandle reflected_method,
                           Handle receiver, bool override, objArrayHandle ptypes,
                           BasicType rtype, objArrayHandle args, bool is_method_invoke, TRAPS) {
      ResourceMark rm(THREAD);
    
      methodHandle method;      // actual method to invoke
      KlassHandle target_klass; // target klass, receiver's klass for non-static
    
      // Ensure klass is initialized
      klass->initialize(CHECK_NULL);
    
      bool is_static = reflected_method->is_static();
      if (is_static) {
        // ignore receiver argument
        method = reflected_method;
        target_klass = klass;
      } else {
        // check for null receiver
        if (receiver.is_null()) {
          THROW_0(vmSymbols::java_lang_NullPointerException());
        }
        // Check class of receiver against class declaring method
        if (!receiver->is_a(klass())) {
          THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), "object is not an instance of declaring class");
        }
        // target klass is receiver's klass
        target_klass = KlassHandle(THREAD, receiver->klass());
        // no need to resolve if method is private or <init>
        if (reflected_method->is_private() || reflected_method->name() == vmSymbols::object_initializer_name()) {
          method = reflected_method;
        } else {
          // resolve based on the receiver
          if (reflected_method->method_holder()->is_interface()) {
            // resolve interface call
            if (ReflectionWrapResolutionErrors) {
              // new default: 6531596
              // Match resolution errors with those thrown due to reflection inlining
              // Linktime resolution & IllegalAccessCheck already done by Class.getMethod()
              method = resolve_interface_call(klass, reflected_method, target_klass, receiver, THREAD);
              if (HAS_PENDING_EXCEPTION) {
              // Method resolution threw an exception; wrap it in an InvocationTargetException
                oop resolution_exception = PENDING_EXCEPTION;
                CLEAR_PENDING_EXCEPTION;
                JavaCallArguments args(Handle(THREAD, resolution_exception));
                THROW_ARG_0(vmSymbols::java_lang_reflect_InvocationTargetException(),
                    vmSymbols::throwable_void_signature(),
                    &args);
              }
            } else {
              method = resolve_interface_call(klass, reflected_method, target_klass, receiver, CHECK_(NULL));
            }
          }  else {
            // if the method can be overridden, we resolve using the vtable index.
            assert(!reflected_method->has_itable_index(), "");
            int index = reflected_method->vtable_index();
            method = reflected_method;
            if (index != Method::nonvirtual_vtable_index) {
              // target_klass might be an arrayKlassOop but all vtables start at
              // the same place. The cast is to avoid virtual call and assertion.
              InstanceKlass* inst = (InstanceKlass*)target_klass();
              method = methodHandle(THREAD, inst->method_at_vtable(index));
            }
            if (!method.is_null()) {
              // Check for abstract methods as well
              if (method->is_abstract()) {
                // new default: 6531596
                if (ReflectionWrapResolutionErrors) {
                  ResourceMark rm(THREAD);
                  Handle h_origexception = Exceptions::new_exception(THREAD,
                         vmSymbols::java_lang_AbstractMethodError(),
                         Method::name_and_sig_as_C_string(target_klass(),
                         method->name(),
                         method->signature()));
                  JavaCallArguments args(h_origexception);
                  THROW_ARG_0(vmSymbols::java_lang_reflect_InvocationTargetException(),
                    vmSymbols::throwable_void_signature(),
                    &args);
                } else {
                  ResourceMark rm(THREAD);
                  THROW_MSG_0(vmSymbols::java_lang_AbstractMethodError(),
                            Method::name_and_sig_as_C_string(target_klass(),
                                                                    method->name(),
                                                                    method->signature()));
                }
              }
            }
          }
        }
      }
    
      // I believe this is a ShouldNotGetHere case which requires
      // an internal vtable bug. If you ever get this please let Karen know.
      if (method.is_null()) {
        ResourceMark rm(THREAD);
        THROW_MSG_0(vmSymbols::java_lang_NoSuchMethodError(),
                    Method::name_and_sig_as_C_string(klass(),
                                                            reflected_method->name(),
                                                            reflected_method->signature()));
      }
    
      // In the JDK 1.4 reflection implementation, the security check is
      // done at the Java level
      if (!(JDK_Version::is_gte_jdk14x_version() && UseNewReflection)) {
    
      // Access checking (unless overridden by Method)
      if (!override) {
        if (!(klass->is_public() && reflected_method->is_public())) {
          bool access = Reflection::reflect_check_access(klass(), reflected_method->access_flags(), target_klass(), is_method_invoke, CHECK_NULL);
          if (!access) {
            return NULL; // exception
          }
        }
      }
    
      } // !(Universe::is_gte_jdk14x_version() && UseNewReflection)
    
      assert(ptypes->is_objArray(), "just checking");
      int args_len = args.is_null() ? 0 : args->length();
      // Check number of arguments
      if (ptypes->length() != args_len) {
        THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), "wrong number of arguments");
      }
    
      // Create object to contain parameters for the JavaCall
      JavaCallArguments java_args(method->size_of_parameters());
    
      if (!is_static) {
        java_args.push_oop(receiver);
      }
    
      for (int i = 0; i < args_len; i++) {
        oop type_mirror = ptypes->obj_at(i);
        oop arg = args->obj_at(i);
        if (java_lang_Class::is_primitive(type_mirror)) {
          jvalue value;
          BasicType ptype = basic_type_mirror_to_basic_type(type_mirror, CHECK_NULL);
          BasicType atype = unbox_for_primitive(arg, &value, CHECK_NULL);
          if (ptype != atype) {
            widen(&value, atype, ptype, CHECK_NULL);
          }
          switch (ptype) {
            case T_BOOLEAN:     java_args.push_int(value.z);    break;
            case T_CHAR:        java_args.push_int(value.c);    break;
            case T_BYTE:        java_args.push_int(value.b);    break;
            case T_SHORT:       java_args.push_int(value.s);    break;
            case T_INT:         java_args.push_int(value.i);    break;
            case T_LONG:        java_args.push_long(value.j);   break;
            case T_FLOAT:       java_args.push_float(value.f);  break;
            case T_DOUBLE:      java_args.push_double(value.d); break;
            default:
              THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), "argument type mismatch");
          }
        } else {
          if (arg != NULL) {
            Klass* k = java_lang_Class::as_Klass(type_mirror);
            if (!arg->is_a(k)) {
              THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), "argument type mismatch");
            }
          }
          Handle arg_handle(THREAD, arg);         // Create handle for argument
          java_args.push_oop(arg_handle); // Push handle
        }
      }
    
      assert(java_args.size_of_parameters() == method->size_of_parameters(), "just checking");
    
      // All oops (including receiver) is passed in as Handles. An potential oop is returned as an
      // oop (i.e., NOT as an handle)
      JavaValue result(rtype);
      JavaCalls::call(&result, method, &java_args, THREAD);
    
      if (HAS_PENDING_EXCEPTION) {
        // Method threw an exception; wrap it in an InvocationTargetException
        oop target_exception = PENDING_EXCEPTION;
        CLEAR_PENDING_EXCEPTION;
        JavaCallArguments args(Handle(THREAD, target_exception));
        THROW_ARG_0(vmSymbols::java_lang_reflect_InvocationTargetException(),
                    vmSymbols::throwable_void_signature(),
                    &args);
      } else {
        if (rtype == T_BOOLEAN || rtype == T_BYTE || rtype == T_CHAR || rtype == T_SHORT)
          narrow((jvalue*) result.get_value_addr(), rtype, CHECK_NULL);
        return box((jvalue*) result.get_value_addr(), rtype, CHECK_NULL);
      }
    }

    Reflection::invoke_method()中调用Reflection::invoke(),然后在Reflection::invoke()方法中,当反射调用的方法是接口方法时,调用Reflection::resolve_interface_call(),该方法依赖LinkResolver::resolve_interface_call()来完成方法的动态链接过程,具体实现就不在这里展示。

    method = resolve_interface_call(klass, reflected_method, target_klass, receiver, CHECK_(NULL));
    methodHandle Reflection::resolve_interface_call(instanceKlassHandle klass, methodHandle method,
                                                    KlassHandle recv_klass, Handle receiver, TRAPS) {
      assert(!method.is_null() , "method should not be null");
    
      CallInfo info;
      Symbol*  signature  = method->signature();
      Symbol*  name       = method->name();
      LinkResolver::resolve_interface_call(info, receiver, recv_klass, klass,
                                           name, signature,
                                           KlassHandle(), false, true,
                                           CHECK_(methodHandle()));
      return info.selected_method();
    }

    如果反射调用的方法是可以被覆盖的方法,例如Animal.print(), Reflection::invoke()最终通过查询虚方法表vtable来确定最终的method。

            // if the method can be overridden, we resolve using the vtable index.
            assert(!reflected_method->has_itable_index(), "");
            int index = reflected_method->vtable_index();
            method = reflected_method;
            if (index != Method::nonvirtual_vtable_index) {
              // target_klass might be an arrayKlassOop but all vtables start at
              // the same place. The cast is to avoid virtual call and assertion.
              InstanceKlass* inst = (InstanceKlass*)target_klass();
              method = methodHandle(THREAD, inst->method_at_vtable(index));
            }

     

    总结

    1.method.invoke()方法支持多态特性,其native实现在方法真正执行之前通过动态连接或者虚方法表来实现。

    2.框架中使用method.invoke()执行方法调用时,初始获取method对象时,可以先调用一次setAccessable(true),使得后面每次调用invoke()时,节省一次方法修饰符的判断,略微提升性能。业务允许的情况下,Field同样可以如此操作。

    3.委托模式可以解决一种方案的多种实现之间自由切换,而代理模式只能根据传入的被代理对象来实现功能。

     

     

    参考文章:

    JAVA深入研究——Method的Invoke方法

    展开全文
  • java中的反射,invoke方法

    千次阅读 2021-03-05 18:03:44
    以下代码简单地介绍了java反射中invoke方法packageorg.curry.tool;importjava.lang.reflect.Method;publicclassInvokeMethods{publicstaticvoidmain(String[]args){Employeeemp=newEmployee(...
  • jdk动态代理—如何执行到invoke方法

    千次阅读 2020-12-04 15:06:48
    先写一个动态代理demo。 接口: public interface Inter { void test(); } 目标类,即需要被代理的类: ... System.out.println("======执行了test方法======"); } } 写一个类生成代理对象: /** *
  • 其次,获取到方法后需要执行该方法才可以获取到返回的数据,所以用到 invoke方法,因为反射的方法没有传参数,所以至需要在里边传入类就行。 最后,将代码附上: /*** 判断trains中是否含有trainClass这个类型的...
  • Unity定时重复调用方法--Invoke方法

    千次阅读 2020-11-01 20:47:37
    Unity定时销毁物体_Invoke方法 本篇讲述如何在unity中定时销毁一个物体,重点是定时调用其他方法的Invoke方法, 通过这个方法也可以实现更多其他的定时功能。 Destory方法: 该方法继承自Object类,需要传入的参数为...
  • 相关文章:静态代理和动态代理的区别和联系 一、动态代理与静态代理的区别。 (1)Proxy类的代码被固定下来,不会...静态代理这个模式本身有个大问题,如果类方法数量越来越多的时候,代理类的代码量是十分庞大的。...
  • java中的反射,invoke方法详解

    千次阅读 2021-02-12 11:52:39
    展开全部就是调用类中的方法e68a843231313335323631343130323136353331333365646239,最简单的用法是可以把方法参数化,invoke(class, method)比如你Test类里有一系列名字相似的方法setValue1、setValue2等等。...
  • 本文解释了如何通过IBMRationalFunctionalTester所提供的两种方法使用这些控件类,用以创建自动化的处理过程:getProperty和invoke。IBM:registered:Rational:registered:FunctionalTester提供了标准接口,便于操作...
  • Java反射之Method的invoke方法实现

    千次阅读 2020-11-11 21:55:35
    然而前段时间研究invoke方法时,发现invoke方法居然包含多态的特性,这是以前没有考虑过的一个问题。那么Method.invoke()方法的执行过程是怎么实现的?它的多态又是如何实现的呢? 本文将从java和JVM的源码实现深入...
  • Method的invoke方法初步了解

    千次阅读 2020-06-28 18:14:35
    1、方法的调用先检查AccessibleObject的override属性是否是true,如果是则表明该方法是复写的方法,可以忽略访问权限的限制,直接访问。如果不是则进行访问权限检测,用sun.reflect.Reflection的...
  • php invoke方法有什么用

    2021-03-24 08:23:15
    php invoke方法是PHP5.3新增的一个魔术方法,该方法可以在创建实例后,直接调用对象,也就是通过函数的方式来使用对象,并且invoke方法也可以带参数。PHP5.3新增了一个叫做__invoke的魔术方法,这样在创建实例后,...
  • C#中的invoke方法

    千次阅读 2020-10-23 09:09:14
    C#中的invoke方法 在用.NET Framework框架的WinForm构建GUI程序界面时,如果要在控件的事件响应函数中改变控件的状态,例如:某个按钮上的文本原先叫“打开”,单击之后按钮上的文本显示“关闭”,初学者往往会...
  • invoke方法的使用

    千次阅读 2019-11-12 09:56:38
  • jdk动态代理invoke方法自动运行原因

    千次阅读 多人点赞 2019-10-17 09:00:20
    想要知道 invoke方法为什么会自动调用我们先要来了解一下这个方法 public interface InvocationHandler { public Object invoke(Object proxy, Method method, Object[] args) 首先 该方法来自于接口...
  • Java反射中Method类invoke方法的用法

    千次阅读 2021-02-26 14:41:54
    invoke()方法的返回值总是对象, //如果实际被调用的方法的返回类型是基本类型数据,那么invoke()方法会把它转换为相应的包装类型的对象, //再将其返回 Object result = addMethod.invoke(invokertester, new ...
  • java反射中的invoke方法

    千次阅读 2020-01-07 00:06:04
    1、invoke是Method类下的方法,只有方法才能调用invoke方法, 2、invoke方法的含义:反射调用实例方法,返回的是实例方法的返回值。 3、哪个方法调用invoke方法,返回的就是哪个方法的返回值。 4、invoke方法的...
  • InvocationHandle的invoke方法

    千次阅读 2017-07-31 22:22:49
    在学习代理模式中接触到了动态代理的相关内容,这是AOP的核心内容。先用一个例子说明 动态代理 的使用 //接口(动态代理只能代理接口) ...//接口实现 :实现了Subject的request()方法 public class RealSubject i
  • 深入解析Java反射(2) - invoke方法

    千次阅读 2020-11-25 23:18:13
    这一节我们来深入研究Method类中的invoke方法,探寻它的奥秘。 注:本篇文章的所有源码都基于OpenJDK 1.8。 引入 即使没有学过反射,大家也一定会见过invoke方法。因为很多方法调用都是靠invoke方法,所以很多异常...
  • method.invoke方法如何捕获异常

    千次阅读 2020-05-25 20:33:32
    普通的异常捕获是捕获不到invoke方法中的异常的。其实java认为用反射来调用方法时,jvm不能在编译期间确定方法的throws 类型,所以方法可能抛出的异常jvm也不能动态确定其类型,而统一抛出InvocationTargetException...
  • 传入多个参数时候invoke方法的使用

    千次阅读 2020-10-03 10:58:38
    在学习jdk的动态代理时,invoke方法里面需要传入多个参数。动态代理也是传入Object[] args,参数数组。如果是多个参数不能直接传入多个参数,需要创建参数数组 狂神说Spring06:静态/动态代理模式 反射之invoke方法 ...
  • EasyExcel导入excel无法导入,发现无法进入监听器的invoke方法的问题解决 重写监听器的hasNext()方法时没有注意到默认返回的是false,导致一进监听器就判断已经没有下一条记录,直接跳出监听器,然后导入就完成,也不会...
  • java.lang.reflect.Proxy类的newProxyInstance...java.lang.reflect.InvocationHandler接口中的invoke(),在代理实例上处理方法调用并返回结果。当与方法关联的代理实例上调用方法时,将在调用处理程序上调用此方法...
  • java反射invoke方法的使用

    千次阅读 2020-03-26 08:25:11
    invoke 主要是用来调用某个类中的方法的,但是他不是通过当前类直接去调用而是通过反射的机制去调用。 在这之前我们先新建一个实体类,一会会用到。 public class TestMode { private static final String TAG =...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 383,487
精华内容 153,394
关键字:

invoke方法

友情链接: DES.zip