Java学习者论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

手机号码,快捷登录

恭喜Java学习者论坛(https://www.javaxxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,购买链接:点击进入购买VIP会员
JAVA高级面试进阶视频教程Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程

Go语言视频零基础入门到精通

Java架构师3期(课件+源码)

Java开发全终端实战租房项目视频教程

SpringBoot2.X入门到高级使用教程

大数据培训第六期全套视频教程

深度学习(CNN RNN GAN)算法原理

Java亿级流量电商系统视频教程

互联网架构师视频教程

年薪50万Spark2.0从入门到精通

年薪50万!人工智能学习路线教程

年薪50万!大数据从入门到精通学习路线年薪50万!机器学习入门到精通视频教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程 MySQL入门到精通教程
查看: 312|回复: 0

[设计模式学习]写一个ArrayList类的动态代理类

[复制链接]
  • TA的每日心情
    开心
    2021-3-12 23:18
  • 签到天数: 2 天

    [LV.1]初来乍到

    发表于 2014-10-31 23:59:59 | 显示全部楼层 |阅读模式
    动态代理可以提供对另一个对象的访问,同时隐藏实际对象的具体事实,代理对象对客户隐藏了实际对象。动态代理可以对请求进行其他的一些处理,在不允许直接访问某些类,或需要对访问做一些特殊处理等,这时候可以考虑使用代理。

        目前 java 开发包中提供了对动态代理的支持,但现在只支持对接口的实现。

    主要是通过 java.lang.reflect.Proxy 类和 java.lang.reflect.InvocationHandler 接口。
        Proxy 类主要用来获取动态代理对象,InvocationHandler 接口用来约束调用者行为。    “写一个 ArrayList 类的代理,其内部实现和 ArrayList 中完全相同的功能,并可以计算每个方法运行的时间。”这是一份考题上的题目,没有答案,来看下实现:  
      
       
       

         
       

         
       
      
    1. import java.lang.reflect.InvocationHandler;
    2. import java.lang.reflect.Method;
    3. import java.lang.reflect.Proxy;
    4. import java.util.ArrayList;
    5. import java.util.List;
    6. import java.util.concurrent.TimeUnit;
    7. /**
    8. * -----------------------------------------
    9. * @描述  TODO
    10. * @作者  fancy
    11. * @邮箱  fancydeepin@yeah.net
    12. * @日期  2012-8-27
    13. * -----------------------------------------
    14. */
    15. public class ProxyApp {
    16.     public static void main(String[] args){
    17.         
    18.         //ArrayList代理,通过代理计算每个方法调用所需时间
    19.         List< Integer> arrayListProxy = (List< Integer>)Proxy.newProxyInstance(
    20.                     /*定义代理类的类加载器,用于创建代理对象,不一定必须是ArrayList,也可以是其他的类加载器*/
    21.             ArrayList.class.getClassLoader(),   
    22.             ArrayList.class.getInterfaces(),     /*代理类要实现的接口列表*/
    23.             new InvocationHandler() {            /*指派方法调用的调用处理程序,这里用了匿名内部类*/
    24.                
    25.                 private ArrayList< Integer> target = new ArrayList< Integer>(); //目标对象(真正操作的对象)
    26.                 /**
    27.                  * 在代理实例上处理方法调用并返回结果
    28.                  * @param proxy     代理对象(注意不是目标对象)
    29.                  * @param method  被代理的方法
    30.                  * @param args         被代理的方法的参数集
    31.                  * @return  返回方法调用结果
    32.                  */
    33.                 @Override
    34.                 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    35.                     
    36.                     long beginTime = System.currentTimeMillis();  //开始时间
    37.                     TimeUnit.MICROSECONDS.sleep(1);
    38.                     Object obj = method.invoke(target, args);          //实际调用的方法,并接受方法的返回值
    39.                     long endTime = System.currentTimeMillis();   //结束时间
    40.                     System.out.println("[" + method.getName() + "] spend " + (endTime - beginTime) + " ms");
    41.                     return obj;   //返回实际调用的方法的返回值
    42.                     
    43.                 }
    44.                
    45.             }
    46.         );
    47.         arrayListProxy.add(2);
    48.         arrayListProxy.add(4);
    49.         System.out.println("--------- 迭代 ---------");
    50.         for(int i : arrayListProxy){
    51.             System.out.print(i + "        ");
    52.         }
    53.     }
    54. }
    复制代码
    后台打印输出结果:
    [add] spend 2 ms
    [add] spend 1 ms
    --------- 迭代 ---------
    [iterator] spend 1 ms
    2 4
    从代码上来看,用到了匿名内部类,这样一来,InvocationHandler 只能用一次,
    如果多个地方都需要用到这样一个相同的 InvocationHandler,可以将其抽象出来成为一个单独的类:
    1. package test;
    2. import java.lang.reflect.InvocationHandler;
    3. import java.lang.reflect.Method;
    4. import java.util.concurrent.TimeUnit;
    5. public class MyInvocationHandler implements InvocationHandler{
    6.     private Object target; //目标对象
    7.    
    8.     public MyInvocationHandler(Object target){
    9.         
    10.         this.target = target;
    11.     }
    12.    
    13.     @Override
    14.     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    15.         
    16.         long beginTime = System.currentTimeMillis();
    17.         TimeUnit.MICROSECONDS.sleep(1);
    18.         Object obj = method.invoke(target, args);
    19.         long endTime = System.currentTimeMillis();
    20.         System.out.println("[" + method.getName() + "] spend " + (endTime - beginTime) + " ms");
    21.         return obj;
    22.         
    23.     }
    24. }
    复制代码
    客户端调用改成:

    1. package example;
    2. import java.lang.reflect.Proxy;
    3. import java.util.ArrayList;
    4. import java.util.List;
    5. public class ProxyApp {
    6.     public static void main(String[] args){
    7.         
    8.         //ArrayList代理,通过代理计算每个方法调用所需时间
    9.         List< Integer> arrayListProxy = (List< Integer>)Proxy.newProxyInstance(
    10.                 /*定义代理类的类加载器,用于创建代理对象,不一定必须是ArrayList,也可以是其他的类加载器*/
    11.             ArrayList.class.getClassLoader(),     
    12.             ArrayList.class.getInterfaces(),       /*代理类要实现的接口列表*/
    13.                         /*指派方法调用的调用处理程序,这里用了匿名内部类*/
    14.             new MyInvocationHandler(new ArrayList< Integer>())   
    15.         );
    16.         arrayListProxy.add(2);
    17.         arrayListProxy.add(4);
    18.         System.out.println("--------- 迭代 ---------");
    19.         for(int i : arrayListProxy){
    20.             System.out.print(i + "        ");
    21.         }
    22.     }
    23. }
    复制代码
      从上面代码看来,客户端知道代理的实际目标对象,还知道怎么样去创建这样一个代理对象,
    如果想把这些信息全部对客户端隐藏起来,可以将这些代码挪到一个类中,将它们封装起来:
    1. package example;
    2. import java.lang.reflect.InvocationHandler;
    3. import java.lang.reflect.Method;
    4. import java.lang.reflect.Proxy;
    5. import java.util.ArrayList;
    6. import java.util.List;
    7. import java.util.concurrent.TimeUnit;
    8. public class ProxyUtil {
    9.     public enum ArrayListProxy {
    10.         PROXY;
    11.         
    12.         private Object target;
    13.         
    14.         ArrayListProxy(){
    15.             this.target = new ArrayList< Object>();
    16.         }
    17.         
    18.   public List getInstance(){
    19.             
    20.     return (List)Proxy.newProxyInstance(ArrayList.class.getClassLoader(), ArrayList.class.getInterfaces(),
    21.                     new InvocationHandler() {
    22.                         
    23.                @Override
    24.       public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    25.                            
    26.         long beginTime = System.currentTimeMillis();
    27.         TimeUnit.MICROSECONDS.sleep(1);
    28.         Object obj = method.invoke(target, args);
    29.         long endTime = System.currentTimeMillis();
    30.         System.out.println("[" + method.getName() + "] spend " + (endTime - beginTime) + " ms");
    31.            return obj;
    32.                            
    33.           }
    34.         });
    35.       }
    36.     }
    37. }
    复制代码
    客户端调用改成:
    1. package example;
    2. import java.util.List;
    3. import example.ProxyUtil.ArrayListProxy;
    4. /**
    5. * -----------------------------------------
    6. * @描述  TODO
    7. * @作者  fancy
    8. * @邮箱  fancydeepin@yeah.net
    9. * @日期  2012-8-27
    10. * -----------------------------------------
    11. */
    12. public class ProxyApp {
    13.     public static void main(String[] args){
    14.         
    15.         List< Integer> arrayListProxy = ArrayListProxy.PROXY.getInstance();
    16.         arrayListProxy.add(2);
    17.         arrayListProxy.add(4);
    18.         System.out.println("--------- 迭代 ---------");
    19.         for(int i : arrayListProxy){
    20.             System.out.print(i + "        ");
    21.         }
    22.         
    23.     }
    24. }
    25. 上面代码中用到了枚举 enum,如果不想用枚举,就改用普通类来实现就行了。
    复制代码



      
      
       
       

         
       

         
       
      
    复制代码
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|Java学习者论坛 ( 声明:本站资料整理自互联网,用于Java学习者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2025-2-25 19:01 , Processed in 0.368991 second(s), 48 queries .

    Powered by Discuz! X3.4

    © 2001-2017 Comsenz Inc.

    快速回复 返回顶部 返回列表