package question3;
import java.lang.reflect.Method;
/*
* 写一个ArrayList类的代理,其内部实现和ArrayList中完全相同的功能,
* 并可以计算每个方法运行的时间。
*
* 解题方式三
* 1.反射机制实现代理调用
* 2.实现统一的代理工厂方法来实现代理的创建
* 3.为该方法的耗时计算实现线程安全,以精度为纳秒计算
* 4.为目标invoke实现线程安全
* 5.实现任意代理,不在局限于ArrayList
* 6.实现参数的动态识别,更精简的参数列表
*
* 优点:相对于第二种方式,将可以支持代理类型的多样化
* 但代理代码方面仍然死板,对于不同功能的代理
* 扔需要编写额外的代理类,但相对于第1 2种,
* 仍然可以节省大量开发时间
*
* 缺点:参数类型动态识别方面仍然存在缺陷,至少来说也不是
* 那么废柴,还是看亮点吧。。。
*
* 注:1秒=1 000 000 000纳秒 jdk api中以毫微秒表示纳秒
*/
public class ArrayListProxy_3
{
/**
* 此代理的目标对象,该成员只有代理类
* 可以持有,所以不应该暴露给用户,而是私有
*/
private Object target;
/**
* 构造函数私有化,该代理仅可通过 {@link #factory(String)}
* 取得实例
*/
private ArrayListProxy_3(String targetType) throws ClassNotFoundException,
InstantiationException, IllegalAccessException
{
target = Class.forName(targetType).newInstance();
System.out.println("create the target instance from "+target.getClass().getName());
}
/**
* 本类的工厂方法
*
* @param targetType 目标类型,该类型应该是完整的<br>
* for example java.util.ArrayList
*/
public static final ArrayListProxy_3 factory(String targetType) throws ClassNotFoundException,
InstantiationException, IllegalAccessException
{
return new ArrayListProxy_3(targetType);
}
/**
* 本类的代理方法,用以实现ArrayList的所有方法的
* 代理调用,并统计耗时,本方法是线程安全的
*
* <p><font color=red>代理方法并不应该因为异常而导致程序终止(退出),
* 而是应该以日志方式记录该异常信息,以表明该代理
* 的使用者存在显式的错误</font>
*
* @param methodName 需要调用的方法名称
* @param parameterTypes 该方法的参数类型列表
* @param parameters 该方法的参数列表
* @return 该方法的返回值;如果出现异常,并不会被抛出
* 控制台仅以错误方式显示该异常的信息,但不会
* 包括异常堆栈信息,而同时返回null
*/
public Object invoke(String methodName, Object... parameters)
{
try
{
Object returnValue = null;
Method method = target.getClass().getMethod(methodName, getParameterTypes(parameters));
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;
}
}
/**
* 根据参数自动识别类型
*
* <p>该方法对于范型实例还可以,因为都提供最基本的
* Object元素访问,其他的实例会发生一些强转异常
*
* <p>本方法是为了实现invoke方法的便捷使用,但会
* 额外消耗调用时间,降低效率
*/
@SuppressWarnings("unchecked")
public Class<? extends Object>[] getParameterTypes(Object[] parameters) throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException
{
if(parameters != null)
{
Class[] class_array = new Class[parameters.length];
for (int i = 0; i < class_array.length; i++)
{
//如果该参数的类型是基本类型,那么保持原类型
if(parameters[i].getClass().isPrimitive())
class_array[i] = parameters[i].getClass();
//如果为包装类型则转换成基本类型
//该处理是针对的自动装箱功能
else if(parameters[i] instanceof Number)
class_array[i] = (Class) parameters[i].getClass().getField("TYPE").get(parameters[i]);
//否则以Object类型传入
else
class_array[i] = Object.class;
//其实还差一步是处理添加集合的方式
//这里的添加集合会走参数为Object的方法
}
return class_array;
}
else
return null;
}
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException
{
/*
* 测试ArrayList的部分
*/
ArrayListProxy_3 proxy;
proxy = ArrayListProxy_3.factory("java.util.ArrayList");
proxy.invoke("add", "qqq");
proxy.invoke("size", null);
proxy.invoke("get", 0);
proxy.invoke("remove", 0);
System.out.println("==============================================>");
/*
* 测试Linkedlist的部分
*/
proxy = ArrayListProxy_3.factory("java.util.LinkedList");
proxy.invoke("add", "aaa");
proxy.invoke("size", null);
proxy.invoke("get", 0);
proxy.invoke("remove", 0);
System.out.println("==============================================>");
/*
* 测试treemap
*/
proxy = ArrayListProxy_3.factory("java.util.TreeMap");
proxy.invoke("put", "asd","efg");
proxy.invoke("remove","asd");
proxy.invoke("get", "asd");
proxy.invoke("size", null);
System.out.println("==============================================>");
}
}
以反射的方式实现的任意代理 可以代理本地方法
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.