A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 黎志文 中级黑马   /  2013-7-21 15:12  /  1927 人查看  /  3 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

本帖最后由 黎志文 于 2013-7-21 15:20 编辑

之前对代理很迷惑,对它没有一点点思路,其实最主要的,是对代理中涉及到的三个方法及其之间的参数传递迷糊,现将这三个方法总结如下,希望能够给正在对代理同样迷糊的童鞋一点帮助:

    1)代理类的方法:代理类的方法一是来自目标类实现的接口中,二是来自Object这个超类。获取接口中的方法,是为了接下来给目标类做代理打下必备基础,
*  这些方法在jvm生成的代理类中,就已全被jvm复写了,至于复写的具体内容是什么,我们无法得知,只能大致地去推断,但是有一点可以明确,在这些复写好了的
*  每个方法的内部,最核心的是调用了一个方法,该方法就是InvocationHandler接口中的invoke(Object proxy,Method method,Object[] obj)方法,我
*  们知道,要调用一个方法,就必须给此方法传递实参(如果该方法存在形参的话), 代理类中每个实现接口的方法的内部都调用了该方法,那么就须给此方法传递
*  实参。
*   这里以Collection中的add(Object obj)方法为例,假设代理类实现了Collection接口,那么代理类在复写add方法时,在add方法的内部,调用invoke
*  方法,并给该方法传递的第一个实参是this,也就是一个代理类对象,传递的第二个实参就是this.getClass().getMetod("add",Object.class),我给它起个
*  名字,叫addMethod,即通过反射 的方式将add方法的名称传递给invoke方法,传递的第三个参数就是add方法中的参数obj,当然,如果代理类的方法存在多个形参,
*  这里就必须将这些形参名称全部传递给invoke方法的第三个参数(这也就是为何invoke方法的第三个参数是一个数组的原因了,用于接收代理方法中的所有参数),
*  将add方法的名称及其参数传递给invoke方法有什么意义呢?请看下面。
*  
*   2)InvocationHandler接口中的invoke方法:这个方法在接收了上述代理类方法传递给它的参数之后(主要是代理类方法的名称及其参数),我们就可以在
*  invoke方法的内部使用这两个参数了,怎么使用呢?可以通过目标类对象,来使用这两个参数:method.invoke(target,obj),这里的method就是add方法,
*  obj就代理类add方法中的参数。
*  
*   3)目标类对象调用的方法:method.invoke(target,args),用目标类对象target来调用method方法(这里的method就已经是add方法了),并给此方法
*  传递的参数就是obj,
*  总之,代理类的add方法将它的名称,以及它接收到的参数传给invoke方法,invoke方法又在其内部通过目标类对象来调用这两个参数。这样到最后,其实还是目标
*  类对象在调用add方法。
*  
*  根据我的理解,可以推断代理类的add方法是这样定义的
*  public boolean add(Object obj)
*  {
*         Object retVal = handler.invoke(this,this.getClass().getMethod("add",Object.class),new Object[]{obj});
*         return (Boolean)retVal; //因为invoke方法的返回值其实就是将目标类方法的返回值提升至Object,所以这里将这个返回值强转成它原本的类型,再传给代理类方法。
*  }
*  而我们在创建InvocationHandler接口的子类对象时,要复写invoke方法,
*  public Object invoke(Object proxy,Method method,Object[] args)
*  {
*        //自定义的拓展代码
*        Object retVal = method.invoke(target,args); //将目标类调用add方法的返回值传给invoke方法
*       //自定义的拓展代码
*         return retVal;
*  }
*  add方法内部调用invoke方法,并给它传递了参数,method接收了add方法的信息,args接收了add方法参数的信息,所以method.invoke(target,args)其实
*  就是目标类对象target在调用add方法,给该方法传递的参数就是代理类add方法中的参数。当然,我们不在invoke方法内部写method.invoke(target,args)
*  也是可以的,但这样一来该代理类方法就没有起到代理的本意。所以,我们在复写invoke方法时,要注意,一定要加上这部分代码。至于拓展的代码,则可根据需
*  要去自定义。
*  
*  proxy.add("hello")---将方法信息和参数信息传递给---> handler.invoke方法 -----再通过目标类对象去使用这两个信息---> method.invoke(target,args)
*                                                                                                                                                                                                           ↓  
*  proxy.add方法 <-------------------再传给------------------ handler.invoke方法 <-----------------------------传给---------------------------- 返回值。

评分

参与人数 1技术分 +1 收起 理由
杨兴庭 + 1 很给力!

查看全部评分

3 个回复

倒序浏览
很不错的总结。。。。。{:soso_e179:}
回复 使用道具 举报
正在学习代理。。学习了
回复 使用道具 举报
正在学习代理。。学习了
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马