package question3;
import java.lang.reflect.Method;
import java.util.ArrayList;
/*
* 写一个ArrayList类的代理,其内部实现和ArrayList中完全相同的功能,
* 并可以计算每个方法运行的时间。
*
* 解题方式二
* 1.反射机制实现代理调用
* 2.实现统一的代理工厂方法来实现代理的创建
* 3.为该方法的耗时计算实现线程安全,以精度为纳秒计算
* 4.为目标ArrayList实现线程安全
*
* 优点:摒弃了第一种方式的大量代码创建量
* 相对于第一种方式,可以调用ArrayList的上层
* 方法和本地方法,而不仅是上层方法
* 缺点:反射方式总归还是会导致目标方法调用耗时多一些
* 而invoke方法的隐式类型方式,不熟悉Arraylist
* 的话很容易出错,同时这样的代理局限性很明显,
* 仅仅只支持ArrayList
*
* 注:1秒=1 000 000 000纳秒 jdk api中以毫微秒表示纳秒
*/
public class ArrayListProxy_2<E>
{
@SuppressWarnings("unchecked")
public static void main(String[] args)
{
ArrayListProxy_2<String> proxy = ArrayListProxy_2.factory();
proxy.invoke("add", new Class[]{Object.class}, new Object[]{"zhangsan"});
proxy.invoke("size", null, null);
//本行如果不注释,会抛异常,因为没有这个方法
//不过并不会导致程序终止
//proxy.invoke("lalalala", null, null);
proxy.invoke("get", new Class[]{int.class}, new Object[]{0});
}
/**
* 此代理的目标ArrayList,该成员只有代理类
* 可以持有,所以不应该暴露给用户,而是私有
*/
private ArrayList<E> target = new ArrayList<E>();
/*
* 为该代理实现工厂方法,并私有化构造方法
* 实现统一的代理创建方式
*/
private ArrayListProxy_2(){}
public static final <E> ArrayListProxy_2<E> factory()
{
return new ArrayListProxy_2<E>();
}
/**
* 本类的代理方法,用以实现ArrayList的所有方法的
* 代理调用,并统计耗时,本方法是线程安全的
*
* <p><font color=red>代理方法并不应该因为异常而导致程序终止(退出),
* 而是应该以日志方式记录该异常信息,以表明该代理
* 的使用者存在显式的错误</font>
*
* @param methodName 需要调用的方法名称
* @param parameterTypes 该方法的参数类型列表
* @param parameters 该方法的参数列表
* @return 该方法的返回值;如果出现异常,并不会被抛出
* 控制台仅以错误方式显示该异常的信息,但不会
* 包括异常堆栈信息,而同时返回null
*/
public Object invoke(String methodName, Class<? extends Object>[] parameterTypes, Object[] parameters)
{
try
{
Object returnValue = null;
Method method = target.getClass().getMethod(methodName, parameterTypes);
long taken = 0;
/*
* 同步实现的目标方法调用以及耗时统计
*/
synchronized (target)
{
if(null != methodName)
{
taken = System.nanoTime();
returnValue = method.invoke(target, parameters);
taken = System.nanoTime() - taken;
}
}
/*
* 控制台输出目标方法调用的详细信息,包括报名,类名,方法名
* 以及实参的参数列表(传入的实际参数列表),数组不在此列。。。
* 并输出返回值和耗时
*/
System.out.print(target.getClass().getName()+"."+method.getName()+"(");
if(null != parameters)
for (int i = 0; i < parameters.length; i++)
{
System.out.print(parameters[i]);
if(i != parameters.length - 1)
System.out.print(", ");
}
System.out.println(") return "+returnValue+" times taken by "+taken+" ns");
/*
* 将返回值返回给使用者
*/
return returnValue;
}
catch (Exception e)
{
/*
* 木有用e.printStackTrace(),运行时异常会导致程序挂掉
* 所以仅以错误方式输出,这里应该是需要写进log里面,log4j
* 找不到了。。。(┬_┬)
*/
System.out.flush();
System.err.println(e.getClass().getName()+":"+e.getMessage());
System.err.flush();
return null;
}
}
}
以反射的方式实现的定向代理
最新推荐文章于 2018-10-17 09:39:00 发布