快速业务通道

用Java动态代理类实现记忆功能 - 编程入门网

作者 佚名技术 来源 NET编程 浏览 发布时间 2012-06-22
ject.getClass().getClassLoader(), object.getClass().getInterfaces(), new Memoizer(object) ); } private Object object; private Map caches = new HashMap(); private Memoizer(Object object) { this.object = object; } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if (method.getReturnType().equals(Void.TYPE)) { // Don''t cache void methods return invoke(method, args); } else { Map cache = getCache(method); List key = Arrays.asList(args); Object value = cache.get(key); if (value == null && !cache.containsKey(key)) { value = invoke(method, args); cache.put(key, value); } return value; } } private Object invoke(Method method, Object[] args) throws Throwable { try { return method.invoke(object, args); } catch (InvocationTargetException e) { throw e.getTargetException(); } } private synchronized Map getCache(Method m) { Map cache = (Map) caches.get(m); if (cache == null) { cache = Collections.synchronizedMap( new HashMap() ); caches.put(m, cache); } return cache; } }

用Java动态代理类实现记忆功能(5)

时间:2010-12-14

当调用静态方法memoize的时候,将会创建一个新的代理实例-也就是一个java.lang.reflect.proxy的实例.实现了一个接口集.这个接口集由object.getClass().getInterfaces()来决定.每个代理实例包含一个java.lang.reflect.InvocationHandler实例来处理这个代理实例调用的相关方法.在我们的例子里,Memoizer就是一个InvocationHandler实例.

当一个方法在代理实例里被调用,比如, calculateBinaryDigit,那么, Memoizer实例里的invoke方法就会被调用,相关信息会传给invoke方法,以决定proxy实例调用了哪个方法,包含参数信息.在我们的例子里,传入Memoizer的java.lang.Method参数是calculateBinaryDigit,而参数信息则是pi需要精确的位数-整数n.在这个基础上,Memoizer能够进一步进行缓存操作的.

在例子里(caches是一个Hashmap,cache是一个map)里用到的Key,主要是传入的方法信息:Method对象和参数对象. 为了实现的简单与通用性,Memoizer有一个关于cache的HashMap caches,每个method是一个key,对应的value为一个cache.然后把参数信息转化成一个List对象,作为cache的Key.使用List是很方便的,同时也可以保证equals()方法,所以能够保证当且仅当参数信息完全相同的时候这个List才相等.

一旦一个cache的Key被创建,那么,计算之前都会先查找这个cache,如果找到,则返回cache里的值.否则,如果带有这些参数的这个方法没有被调用过,那么,则会通过invoke来调用这个method.在我们的例子里, 实例PiBinaryDigitsCalculator 里的calculateBinaryDigit方法将会通过invoke被调用.而且计算结果将会被存在cache里.

何时使用Memoizer

作为一条通用的规则,Memoizer能够在任何需要传统的cache的时候使用-比如上面提到的例子. 特别地,接口里每个需要使用记忆功能的method需要满足下面几条条件:

1. 这个method的返回值最好不要每次调用都会改变

2. 这个method不要有副效应

3. 这个method的参数是确定的,非mutable的.

显然,如果每次调用这个method返回值都不同,那么cache就毫无用处了.同样也是很重要的一点是,因为有副效应的method不会被重复,所以这个method不能有副效应(method自动更新某些状态).当然,void方法除外.

同样,memorize一个带有未定(mutable)参数的method是很危险的,因为,要把这些参数储存到hashmap里会是很危险的一件事.根据Map的定义,当这个Map里的key发生改变,Map是不知道的.所以,当你执行了一次

凌众科技专业提供服务器租用、服务器托管、企业邮局、虚拟主机等服务,公司网站:http://www.lingzhong.cn 为了给广大客户了解更多的技术信息,本技术文章收集来源于网络,凌众科技尊重文章作者的版权,如果有涉及你的版权有必要删除你的文章,请和我们联系。以上信息与文章正文是不可分割的一部分,如果您要转载本文章,请保留以上信息,谢谢!

分享到: 更多

Copyright ©1999-2011 厦门凌众科技有限公司 厦门优通互联科技开发有限公司 All rights reserved

地址(ADD):厦门软件园二期望海路63号701E(东南融通旁) 邮编(ZIP):361008

电话:0592-5908028 传真:0592-5908039 咨询信箱:web@lingzhong.cn 咨询OICQ:173723134

《中华人民共和国增值电信业务经营许可证》闽B2-20100024  ICP备案:闽ICP备05037997号